Автор: Орехов Роман aka tripsin
function AdjustLineBreaks(const S: string [;
Style: TTextLineBreakStyle]): string;
Вот так определена эта функция в SysUtils:
TTextLineBreakStyle = (tlbsLF,
tlbsCRLF);
function AdjustLineBreaks(const S: string;
Style: TTextLineBreakStyle =
{$IFDEF
LINUX} tlbsLF {$ENDIF}
{$IFDEF
MSWINDOWS} tlbsCRLF {$ENDIF}): string;
(А в модуле ComCtrls.pas эта функция написана на ассемблере для работы с PChar:
function AdjustLineBreaks(Dest, Source: PChar):
Integer; assembler;
)
Функция AdjustLineBreaks приводит строку S к формату установленной OS, преобразуя символы перевода строки (одиночные символы возврата каретки (#13), перевода строки (#10), и пары CR-LF) применительно к данной ОС. Файлы, копируемые из систем Unix и Macintosh, содержат иные символы окончания строк, чем могут "ввести в заблуждение" многие программы DOS и Windows. (В Macintosh используется только символ возврата каретки; в Unix - только символ перевода строки.)
Второй необязательный параметр позволяет управлять форматированием. Ты можешь адаптировать переносы строк, как под Windows (tlbsCRLF), так и под Unix (tlbsLF). По умолчанию он определяется установленной ОС.
var UnixStr: String;
begin // Преобразуем текст под Unix
UnixStr :=
AdjustLineBreaks(Memo1.Text, tlbsLF);
end;
Эта функция часто может тебе понадобиться, чтобы общаться с серверами в сети, т.к. серверы чаще всего работают по никсами (а ты конечно под Виндой :) ).
Для примера переделаем WhoIs-клиент из всеми любимой ДГХ (стр. 142 «Их разыскивают бойцы 139-го порта»). Там, чтобы отформатировать полученную от сервера строку, написан цикл, сканирующий строку на символ #10 и делящий текст на кусочки. Мы сделаем все это в одной строке (для надежности я добавил обработку ошибок):
procedure TForm1.btnFindClick(Sender: TObject);
var
FindResult: String;
begin
ResultMemo.Clear;
try
FindResult :=
IdWhoIs.WhoIs(edtDomain.Text); // Получаем данные
// Обработка – всего одна
строка
ResultMemo.Text :=
AdjustLineBreaks(FindResult);
except
on E: Exception do
ResultMemo.Lines.Add('ОШИБКА: ' + E.Message);
end;
end;
type TRepiaceFlags = set of (rfReplaceAll,
rfIgnoreCase);
function StringReplace(const S,
OldSubStr, NewSubStr: string; Flags: TReplaceFlags):
string;
StringReplace возвращает копию S, где OldSubStr заменена на NewSubStr. Если Flags содержит rfReplaceAll, заменяются все вхождения OldSubStr; иначе заменяется только первое вхождение. Поиск OldSubStr выполняется с учетом регистра, если только не включен флаг rflgnoreCase.
Пример замены текста в TMemo:
procedure TForm1.Button1Click(Sender:
TObject);
begin
Memo1.Lines.Add('Зачем ты учишь
Delphi?');
end;
procedure TForm1.Button2Click(Sender:
TObject);
begin
Memo1.Text :=
StringReplace(Memo1.Text, 'ты учишь', 'он учит', [rfReplaceAll,
rfIgnoreCase]);
end;
function WrapText(const Line, BreakStr:
string; BreakChars: TSysCharSet; MaxCol: Integer): string;overload;
function WrapText(const Line: string;
MaxCol: Integer = 45): string;overload;
Функция WrapText возвращает копию Line, разбитую на
несколько строк шириной MaxCol столбцов. Каждая строка разбивается, когда ее
длина доходит до MaxCol символов. Разбиение производится там, где есть
символы из множества
BreakChars.
При нахождении символа из
BreakChars
,
после него вставляется строка
BreakStr.
(В Delphi 5 как существующие переводы строк рассматриваются символы
#13 и #10, независимо от BreakStr.)
Вторая форма WrapText использует [' ', ' -' , #9] (пробел, дефис, табуляция)
в качестве BreakChars и #13#10 (возврат каретки,
перевод строки) в качестве BreakStr. Получается эта форма просто переносит
строку по словам.
Сама Delphi к этой функции в своих модулях не обращается. Для разных компонентов пишутся аналоги с другими названиями. Я не додумался до сколько-нибудь полезного примера, т.к. например в TMemo и TRichEdit это свойство уже реализовано.
В моем примере TListBox заполняется строками, примерно, как в TMemo и ширина и количество строк меняются, при изменении размера TListBox. Также в примере есть алгоритм подгонки ширины строк к ширине окна:
procedure
TForm1.FormResize(Sender: TObject);
var
S: String;
DC: HDC;
Metrics: TTextMetric;
CharsInWidth:
Integer; //Сколько символов влезет в ширину окна
OldMapMode: Integer;
begin
S := 'Очень
длинная строка, которую мы сейчас разбиваем на ';
S := S + 'кусочки и заполняем ими
строки TListBox по всей ширине. ';
S := S + 'Ширину TListBox мы меняем,
изменяя размеры формы, ';
S := S + 'т.к.
у
TListBox свойство Align
равно
alClient.';
DC := GetWindowDC(ListBox1.Handle); //
Получаем контекст окна
SelectObject(DC,
ListBox1.Font.Handle);//Выбираем в него шрифт окна
OldMapMode :=
GetMapMode(DC);// Запоминаем старый режим отображения
SetMapMode(DC, MM_TEXT);
//Устанавливаем отображение в пикселях
GetTextMetrics(DC,
Metrics); //Получаем параметры шрифта
SetMapMode(DC,
OldMapMode);//Восстанавливаем режим отображения
ReleaseDC(ListBox1.Handle, DC);
//Освобождаем контекст
//Получаем количество средних символов
на ширину окна (6 - подобрано)
CharsInWidth :=
ListBox1.ClientWidth div Metrics.tmAveCharWidth - 6;
ListBox1.Clear; //Очищаем
TListBox
ListBox1.Items.Text :=
WrapText(S, CharsInWidth); //Заполняем
TListBox
Caption := 'Количество
строк в ListBox = ' +
IntToStr(ListBox1.Count);
end;
function IsValidIdent(const Ident: string):
Boolean;
Функция IsValidIdent возвращает True, если Ident содержит корректный идентификатор Delphi Pascal, т. е. строку, первый символ которой является буквой или подчеркиванием: ['A'..'Z', 'a'..'z', '_'] ,а последующие символы - буквами, цифрами или символами подчеркивания: ['A'..'Z', 'a'..'z', '0..'9', '_'].
Наверняка пригодится где-нибудь при разработке компонентов для проверки корректности установленных свойств. Например Delphi использует эту функцию при установке имени компонента TComponent.Name.
Хочется показать определение этой функции. Смотри какой простой и правильный код:
function IsValidIdent(const Ident: string):
Boolean;
const
Alpha = ['A'..'Z', 'a'..'z', '_'];
AlphaNumeric = Alpha + ['0'..'9'];
var
I: Integer;
begin
Result := False;
if (Length(Ident) = 0) or not
(Ident[1] in Alpha) then Exit;
for I := 2 to Length(Ident) do if not
(Ident[I] in AlphaNumeric) then Exit;
Result := True;
end;
function LastDelimiter(const Delimiters,
S : string): Integer;
Функция LastDelimiter возвращает индекс последнего (самого правого) вхождения любого из символов Delimters в строке S. Если ни один из символов Delimiters не присутствует в S, LastDelimiter возвращает ноль. Delimiters не может быть многобайтовой строкой, и нельзя использовать #0 в качестве одного из разделителей.
Может, например, понадобиться для разбора пути к файлу на каталоги: от конечного к корню диска.
А я для примера написал функцию, которая выводит слова в предложении в обратном порядке:
function ReverseString(S: String): String;
var
delim: String;
LastDelim: Integer;
begin
delim := ' '; // разделитель - пробел
Result := ''; // Обнуляем на всякий
случай
repeat
// Получаем последний
пробел
LastDelim :=
LastDelimiter(delim, S);
// Копируем в newstr из
tmpstr слово после пробела + пробел
Result := Result + Copy(S,
LastDelim + 1, Length(S)-LastDelim) + delim;
// Укорачиваем tmpstr на
последнее слово
Delete(S,LastDelim,
Length(S)-LastDelim + 1);
until LastDelim = 0; // Работаем пока
не кончатся пробелы
Result := TrimRight(Result); //
Удаляем лишний пробел на конце
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := 'Ехал грека через реку.';
end;
procedure TForm1.Button1Click(Sender:
TObject);
begin
Edit1.Text := ReverseString(Edit1.Text);
end;
При работе с PChar для тех же целей используется функция AnsiStrRScan:
function AnsiStrRScan(Str: PChar; Chr: Char):
PChar;
Функция AnsiStrRScan выполняет поиск последнего (самого правого) вхождения символа Chr в Str и возвращает указатель на символ в строке Str или nil, если символ не найден.
function AnsiQuotedStr(const S:
string; Quote: Char): string;
Функция AnsiQuotedStr возвращает копию S, заключенную в кавычки. Символ кавычек указан в параметре Quote. Вхождения Quote в S повторяются и в результирующей строке. Эта функция предполагает, что в S нет символов #0 (кроме #0, находящегося за концом строки).
function
AnsiExtractQuotedStr(var Src: PChar; Quote: Char): string;
Функция AnsiExtractQuotedStr выбирает из Src строку, заключенную в кавычки. Первый символ Src должен быть равен Quote, иначе функция сразу завершается, возвращая пустую строку. Если это условие выполняется, строка, заключенная в символы кавычек, копируется и возвращается в качестве результата функции. Повторяющиеся символы кавычек преобразуются в одиночные кавычки. Src изменяется, указывая теперь на символ сразу за закрывающей кавычкой. Если в Src нет закрывающей кавычки, то Src присваивается указатель на завершающий байт #0, и функция возвращает весь текст до конца строки.
Эти функции могут тебе понадобится при работе с файлами, при записи-чтении информации. Delphi использует эти функции при чтении-записи свойства TStrings.CommaText.
Если хочешь знать еще больше, то запускай Delphi, создавай проект по умолчанию и, удерживая кнопочку CTRL кликай мышкой по слову SysUtils в секции uses. Смещай взгляд свой в левую сторону окна с кодом. И будет там окно Code Explorer. И когда нажмешь ты на плюсик слева от папочки Procedures, то будет тебе счастье. Изучай.
Опубликована на VR-online в 2006 г.