2. Работа со строками.
2.1. Поиск подстроки в строке.
Обычно программист, перешедший с Pascal на Delphi, сам пишет функцию поиска подстроки в строке. Выглядит она примерно так:
Function FindSubStrInStr(Const Str,SubStr:string):Boolean;
Var
i,j:integer;
Begin
Result:=false;
For i:=1 to Length(str) do
begin
If (Str[i]=SubStr[1]) and (Length(substr)<=Length(Str)-(i-1)) then
begin
Result:=true;
For j:=2 to Length(SubStr) do
begin
If SubStr[j]<>Str[i+j-1] then
begin
Result:=false;
Break;
End;
End;
End;
If Result Then
Break;
End;
End;
Я написал и отладил эту функцию где-то за 3 минуты, но я уже, когда писал что-то подобное и имел представление что мне нужно. А теперь давайте обратимся к стандартному модулю System. В нем есть замечательная функция Pos.
Функция Pos:
Параметры:
1. Подстрока, тип string.
2. Строка, тип string.
Возвращаемое значение:
Тип integer. Функция возвращает индекс первого символа подстроки в строке. Если подстрока не найдена – 0.
И что же у нас получается? Программист, не знающий о функции Pos потратит минуты 3, пока будет писать свою. Программист, знающий о существовании этой функции потратит на ту же задачу секунд десять. Однако описание этой функции все-таки иногда встречается в книгах.
2.2. Подсчет вхождений подстроки в строку.
Теперь давайте рассмотрим вторую похожую задачу. Нужно подсчитать количество вхождение подстроки в строку. Перепишем нашу функцию:
Function CountSubStrInStr(Const Str, SubStr:string):Integer;
Var
i,j:integer;
find:Boolean;
Begin
Result:=0;
For i:=1 to length(str) do
begin
Find:=false;
If (Str[i]=SubStr[1]) and (Length(substr)<=Length(Str)-(i-1)) then
begin
Find:=true;
For j:=2 to Length(SubStr) do
begin
If SubStr[j]<>Str[i+j-1] then
begin
Find:=false;
Break;
End;
End;
End;
If Find Then
Inc(Result);
End;
End;
На эту функцию я так же потратил где-то три минуты. А можно подключить к проекту модуль StrUtils в котором есть функция PosEx.
Функция PosEx:
Параметры:
1. Подстрока, тип string.
2. Строка, тип string.
3. Смещение (индекс символа, с которого начинается поиск), тип integer;
Возвращаемое значение:
Тип integer. Функция возвращает индекс первого символа подстроки в строке. Если подстрока не найдена – 0.
Теперь функция CountSubStrInStr будет выглядеть так:
Function CountSubStrInStr(Const Str, SubStr:string):Integer;
var
i:integer;
begin
Result:=0; //Значение по-умолчанию 0 (подстрок не найдено).
i:=1; //Начинаем поиск с первого символа.
repeat
i:=PosEx(SubStr,Str,i); //Присваиваем i результат работы PosEx.
if i<>0 then //Если подстрока найдена…
begin
Inc(Result); //…увеличиваем результат на единицу…
i:=i+Length(SubStr); //…и увеличиваем значение i на длину подстроки.
end;
until i=0; //Выходим из цикла, когда подстрок больше (вообще) не найдено.
end;
По-моему, смориться куда лучше, да и скорость выполнения значительно выше.
2.3 Разбить предложение на слова.
Это задача является одной из моих любимых. Помниться еще на первом курсе на её решение на Pascal потратил минут 40. Потом как-то, пришлось решать заново уже на Delphi, и минут за 10 накидал такую процедуру:
Procedure DivideString(const Str:string; StrList:TStrings);
Type
Mnoj=set of char;
Var
i:integer;
subs:string;
Сonst
Mn:Mnoj=['А'..'Я', 'а'..'я', '0'..'9', '-', #39];
Begin
subs:='';
for i:=1 to length(str) do
begin
if not (str[i] in Mn) then
Continue;
subs:=subs+str[i];
if (not (str[i+1] in Mn)) or (i=length(str)) then
begin
StrList.Add(subs);
subs:='';
end;
end;
End;
Она вполне работоспособна и отлично справляется со своими обязанностями, разбивая строку за один проход (а ведь были предложения сначала разбить предложение на слова, используя в качестве разделителей только пробелы, а потом еще и знаки препинания в другом цикле отсекать). Но вместо того, чтобы тратить 10 минут, можно потрать одну, и использовать в коде функцию ExtractStrings.
Функция ExtractStrings:
Параметры:
1. Множество символов используемых в качестве делителей, тип TSysCharSet.
2. Множество символов, которые будут игнорироваться, только если они находятся в начале строки, тип TSysCharSet.
3. Строка, тип PChar.
4. Список строк, в который будут добавлены получившиеся в результате разбиения слова, тип TStrings.
Возвращаемое значение:
Тип integer. Функция возвращает количество получившихся слов в результате разбиения строки.
Единственный минус, найденный мной в работе этой функции, это не возможность обработать символ «’» в сочетании с русскими буквами. То есть если мы введет строку: «Computed solution d’Alembert’s force», - то получим вполне ожидаемые четыре слова. А если: «Найденное решение и есть д'Аламберова сила», - функция просто откажется разбивать строку после «’» вернув оставшееся как одно слово. То есть мы получим пять слов вместо шести.
2.1. Поиск подстроки в строке.
Обычно программист, перешедший с Pascal на Delphi, сам пишет функцию поиска подстроки в строке. Выглядит она примерно так:
Function FindSubStrInStr(Const Str,SubStr:string):Boolean;
Var
i,j:integer;
Begin
Result:=false;
For i:=1 to Length(str) do
begin
If (Str[i]=SubStr[1]) and (Length(substr)<=Length(Str)-(i-1)) then
begin
Result:=true;
For j:=2 to Length(SubStr) do
begin
If SubStr[j]<>Str[i+j-1] then
begin
Result:=false;
Break;
End;
End;
End;
If Result Then
Break;
End;
End;
Я написал и отладил эту функцию где-то за 3 минуты, но я уже, когда писал что-то подобное и имел представление что мне нужно. А теперь давайте обратимся к стандартному модулю System. В нем есть замечательная функция Pos.
Функция Pos:
Параметры:
1. Подстрока, тип string.
2. Строка, тип string.
Возвращаемое значение:
Тип integer. Функция возвращает индекс первого символа подстроки в строке. Если подстрока не найдена – 0.
И что же у нас получается? Программист, не знающий о функции Pos потратит минуты 3, пока будет писать свою. Программист, знающий о существовании этой функции потратит на ту же задачу секунд десять. Однако описание этой функции все-таки иногда встречается в книгах.
2.2. Подсчет вхождений подстроки в строку.
Теперь давайте рассмотрим вторую похожую задачу. Нужно подсчитать количество вхождение подстроки в строку. Перепишем нашу функцию:
Function CountSubStrInStr(Const Str, SubStr:string):Integer;
Var
i,j:integer;
find:Boolean;
Begin
Result:=0;
For i:=1 to length(str) do
begin
Find:=false;
If (Str[i]=SubStr[1]) and (Length(substr)<=Length(Str)-(i-1)) then
begin
Find:=true;
For j:=2 to Length(SubStr) do
begin
If SubStr[j]<>Str[i+j-1] then
begin
Find:=false;
Break;
End;
End;
End;
If Find Then
Inc(Result);
End;
End;
На эту функцию я так же потратил где-то три минуты. А можно подключить к проекту модуль StrUtils в котором есть функция PosEx.
Функция PosEx:
Параметры:
1. Подстрока, тип string.
2. Строка, тип string.
3. Смещение (индекс символа, с которого начинается поиск), тип integer;
Возвращаемое значение:
Тип integer. Функция возвращает индекс первого символа подстроки в строке. Если подстрока не найдена – 0.
Теперь функция CountSubStrInStr будет выглядеть так:
Function CountSubStrInStr(Const Str, SubStr:string):Integer;
var
i:integer;
begin
Result:=0; //Значение по-умолчанию 0 (подстрок не найдено).
i:=1; //Начинаем поиск с первого символа.
repeat
i:=PosEx(SubStr,Str,i); //Присваиваем i результат работы PosEx.
if i<>0 then //Если подстрока найдена…
begin
Inc(Result); //…увеличиваем результат на единицу…
i:=i+Length(SubStr); //…и увеличиваем значение i на длину подстроки.
end;
until i=0; //Выходим из цикла, когда подстрок больше (вообще) не найдено.
end;
По-моему, смориться куда лучше, да и скорость выполнения значительно выше.
2.3 Разбить предложение на слова.
Это задача является одной из моих любимых. Помниться еще на первом курсе на её решение на Pascal потратил минут 40. Потом как-то, пришлось решать заново уже на Delphi, и минут за 10 накидал такую процедуру:
Procedure DivideString(const Str:string; StrList:TStrings);
Type
Mnoj=set of char;
Var
i:integer;
subs:string;
Сonst
Mn:Mnoj=['А'..'Я', 'а'..'я', '0'..'9', '-', #39];
Begin
subs:='';
for i:=1 to length(str) do
begin
if not (str[i] in Mn) then
Continue;
subs:=subs+str[i];
if (not (str[i+1] in Mn)) or (i=length(str)) then
begin
StrList.Add(subs);
subs:='';
end;
end;
End;
Она вполне работоспособна и отлично справляется со своими обязанностями, разбивая строку за один проход (а ведь были предложения сначала разбить предложение на слова, используя в качестве разделителей только пробелы, а потом еще и знаки препинания в другом цикле отсекать). Но вместо того, чтобы тратить 10 минут, можно потрать одну, и использовать в коде функцию ExtractStrings.
Функция ExtractStrings:
Параметры:
1. Множество символов используемых в качестве делителей, тип TSysCharSet.
2. Множество символов, которые будут игнорироваться, только если они находятся в начале строки, тип TSysCharSet.
3. Строка, тип PChar.
4. Список строк, в который будут добавлены получившиеся в результате разбиения слова, тип TStrings.
Возвращаемое значение:
Тип integer. Функция возвращает количество получившихся слов в результате разбиения строки.
Единственный минус, найденный мной в работе этой функции, это не возможность обработать символ «’» в сочетании с русскими буквами. То есть если мы введет строку: «Computed solution d’Alembert’s force», - то получим вполне ожидаемые четыре слова. А если: «Найденное решение и есть д'Аламберова сила», - функция просто откажется разбивать строку после «’» вернув оставшееся как одно слово. То есть мы получим пять слов вместо шести.