Александр Шабля дата публикации 05-10-2004 16:10 Использование VBScript RegExp в DelphiРегулярные выражения (RegExp - regular expression) поддерживаются и широко используются в Perl, php, Java, C# и др. языках и интерпретаторах. Этот инструмент используется разработчиками для комплексного поиска соответствий выражению (паттерну) в текстовых строках согласно алгоритму поиска. Подробнее о синтаксисе VBScript Regular Expression можно почитать
в MSDN.
Фирма Borland не включила в свою библиотеку этот часто очень необходимый инструмент.
Эту ситуацию попытался исправить Андрей Сорокин, написав замечательный компонент
TRegExpr
(статья на Королевстве "Текст с высоты птичьего полета или Регулярные выражения").
Однако возможность использовать регулярные выражения в Delphi существует и без этого компонента.
Эта возможность предоставлена фирмой Microsoft в библиотеке VBScript (vbscript.dll версии 5.0 и выше),
поставляемой в составе Windows, начиная с версии 98. Скачать обновления VBScript
можно здесь
или здесь.
Для подключения RegExp необходимо импортировать библиотеку типов Microsoft VBScript Regular Expressions и создать модуль библиотеки типов (смотрите рисунок).
В библиотеку будут включены объекты (интерфейсы) RegExp, MatchCollection, Match, SubMatches и класс-наследник TOLEServer TRegExp.
Для использования в uses включим сгенерированный модуль VBScript_RegExp_55_TLB.pas.
Объект VBScript RegExp (IRegExp2) имеет 4 свойства и 3 метода.
Свойства объекта RegExp:
Свойство | Назначение |
Pattern | Строка, содержащая регулярное выражение. Должна быть задана до использования методов RegExp |
IgnoreCase | Тип Boolean. Если True, то игнорирует регистр символов, по-умолчанию False. Соответствует модификатору "i". |
Global | Тип Boolean. Если True, то RegExp будет пытаться найти все возможные соответствия в строке. Соответствует модификатору "g". |
Multiline | Тип Boolean. Если True, то RegExp будет поддерживать многострочный режим, по-умолчанию False. Соответствует модификатору "m". |
|
Другие модификаторы (x, s, r и др.) в выражениях VBScript RegExp не поддерживаются.
Методы объекта RegExp:
Метод | Назначение |
Test(search-string) | Тестирует строку search-string на соответствие паттерну. В случае удачи возвращает True. |
Replace(search-string, replace-string) | Метод имеет два аргумента: строку, в которой будет осуществляться поиск и строку замены. Все найденные соответствия в строке search-string, заданные в Pattern, будут замещены значениями, указанными в строке замены replace-string. |
Excecute(search-string) | Работает как Test, только все найденные соответвия в строке search-string, заданные в Pattern, будут возвращены в коллекции MatchCollection (см. ниже), содержащей объекты Match. |
|
Содержит коллекцию объектов соответствия Match. Имеет два свойства: Count возвращает количество найденных соответствий, Item содержит объект Match с индексом от 0 до Count - 1. В VBScript RegExp версии 5.5 Item является свойством default, т.е. к свойству Item обращаться не обязательно, т.е. при обращении к объекту типа Matches Item можно опускать.
Объект Match (IMatch2) содержит найденное в строке соответствие, заданное в паттерне поиска. Имеет 4 свойства:
Метод | Назначение |
FirstIndex | Позиция найденного соответствия в строке |
Length | Длина найденной строки |
Value | Текст найденного соответствия |
SubMatches | Колекция субсоответствий. Субсоответствия задаются группировкой с помощью круглых скобок "(" и ")" (см. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/jsgrpregexpsyntax.asp). |
|
Содержит коллекцию субсоответствий. Это как бы соответствия в соответствии. Имеет два свойства: Count - количество найденных субсоответствий и Item (default - можно опустить) возвращает текст найденного субсоответствия с индексом от 0 до Count - 1.
Например, задан RegExp паттерн '(\d*)\.?(\d*)',
строка поиска '123.45',
тогда коллекция SubMatches вернет нам Count = 2, Item[0] = '123' и Item[1] = '45'.
Примечание:
при использовании библиотеки типов VBScript RegExp версии 1.0 свойство Item не является default и его нужно указывать явно. Также отсутсвуют свойство Multiline у объекта RegExp (IRegExp) и свойство SubMatches у объекта Match (IMatch).
Разбор строки URL на составляющие
пример взят с сайта MSDN
procedure TForm1.Button1Click(Sender: TObject);
var
R: TRegExp;
mc: MatchCollection;
m: Match;
sm: SubMatches;
i, j: Integer;
begin
R := TRegExp.Create(Self);
try
R.Pattern := '(\w+):\/\/([^/:]+)(:\d*)?([^#]*)(.*)';
R.IgnoreCase := True;
R.Global := False;
Memo1.Lines.Clear;
mc := R.Execute(' http://msdn.microsoft.com:80/sctipting/default.htm#123')
as MatchCollection;
if mc.Count > 0 then begin
for i := 0 to mc.Count - 1 do begin
m := mc[i] as Match;
Memo1.Lines.Add(Format(' Match[%d] = "%s"', [i, m.Value]));
sm := m.SubMatches as SubMatches;
for j := 0 to sm.Count - 1 do
Memo1.Lines.Add(Format(' SubMatch[%d] = "%s"', [j,
VarToStr(sm.Item[j])]));
end;
end;
finally
m := nil;
sm := nil;
mc := nil;
R.Free;
end;
end;
| |
Теперь рассмотрим подробнее.
В строке R.Pattern := '(\w+):\/\/([^/:]+)(:\d*)?([^#]*)(.*)'
записываем паттерн регулярного выражения.
Далее в mc := R.Execute(' http://msdn.microsoft.com:80/sctipting/default.htm#123') as MatchCollection;
получаем коллекцию найденных соответсвий (MatchCollection).
Получаем объект Match в переменную m := mc[i] as Match; и субсоответствия в переменную
sm := m.SubMatches as SubMatches;
Результатом работы данного примера в Memo1 будет записано следующее:
Match[0] = "http:
SubMatch[0] = "http"
SubMatch[1] = "msdn.microsoft.com"
SubMatch[2] = ":80"
SubMatch[3] = "/sctipting/default.htm"
SubMatch[4] = "#123"
| |
Где первая строка - это найденное соответствие Match, а остальные - субсоответствия (SubMatches).
пример взят с сайта MSDN
procedure TForm1.Button2Click(Sender: TObject);
var
mc: MatchCollection;
S: String;
begin
with TRegExp.Create(Self) do
try
Pattern := Format('[-+]?([0-9]*\%s)?[0-9]+([eE][-+]?[0-9]+)?',
[DecimalSeparator]);
IgnoreCase := True;
Global := True;
S := '';
mc := Execute('5.23') as MatchCollection;
if mc.Count = 1
then ShowMessageFmt('Число "%s" задано верно', [(mc [0] as Match).Value])
else ShowMessage('Это не число!');
finally
mc := nil;
Free;
end;
end;
| |
пример взят с сайта www.regular-expressions.info
procedure TForm1.Button3Click(Sender: TObject);
function IsValidDate(const ADate: String): Boolean;
var
mc: MatchCollection;
sm: SubMatches;
d, m, y: Integer;
begin
Result := False;
with TRegExp.Create(Self) do
try
Pattern := Format('(0?[1-9]|[12][0-9]|3[01])\%0:s(0?[1-9]|1[012])\%0:s((19|20)?\d\d)',
[DateSeparator]);
Global := True;
mc := Execute(ADate) as MatchCollection;
if mc.Count = 1 then begin
sm := (mc[0] as Match).SubMatches as SubMatches;
if sm.Count < 3 then Exit;
d := StrToInt(sm.Item[0]);
m := StrToInt(sm.Item[1]);
y := StrToInt(sm.Item[2]);
if sm.Item[3] = '' then y := y +
Trunc(StrToInt(FormatDateTime('yyyy', Date)) / 100) * 100;
if (d = 31) and ((m = 4) or (m = 6) or (m = 9) or (m = 11))
then Exit
else
if m = 2 then begin
if d >= 30 then Exit;
if (d = 29) and not ((y mod 4 = 0) and ((y mod 100 <> 0) or
(y mod 400 = 0)))
then Exit;
end;
Result := True;
end;
finally
sm := nil;
mс := nil;
Free;
end;
end;
begin
if IsValidDate('29.02.04') then ShowMessage('OK') else Beep;
end;
| |
пример взят с сайта www.regular-expressions.info
procedure TForm1.Button4Click(Sender: TObject);
var
R: TRegExp;
begin
R := TRegExp.Create(Self);
try
R.Pattern := '([^,]*)(,\1)+(?=,|$)';
R.IgnoreCase := True;
R.Global := True;
ShowMessage(R.Replace('раз,два,три,три,четыре,пять,пять,шесть,семь,,девять'#10 +
'1,2,3,3,4,5,5,6,7,,9', '$1'));
finally
R.Free;
end;
end;
| |
пример взят с сайта MSDN
procedure TForm1.Button5Click(Sender: TObject);
var
R: TRegExp;
begin
R := TRegExp.Create(Self);
try
R.Pattern := '([a-zа-я]+) \1';
R.IgnoreCase := True;
R.Global := True;
R.Multiline := True;
ShowMessage(R.Replace('Стоимость стоимость газолина все все растет растет?'#10 +
'Is is the cost of of gasoline going up up?', '$1'));
finally
R.Free;
end;
end;
| |
- является платформозависимой;
- требуется наличие библиотеки VBScript (vbscript.dll) версии 5.0 и выше на клиентском компьютере (поставляется в составе Windows версии 98 и выше);
- объект RegExp разбивается на другие объекты (MatchCollection, SubMatches), которые нужно обрабатывать в отдельных циклах;
- не поддерживается Lookbehind утверждение (assertion);
- при ошибке в выражении (Pattern) возникает не информативное исключение с текстом ошибки "OLE Error 800A1399".
Для сравнения была создана процедура, в которой использовались методы Exec(ute) и Replace. Скорость обработки определялась с помощью тиков (функция WinAPI GetTickCount). Для теста был выбран .pas файл, содержащий 1031 строку.
Первый тест был проведен для глобальной замены по всему тексту. Скорость работы VBScript RegExpr от фирмы Microsoft оказалась " в 5-6 раз выше.
Второй тест на скорость включал построчную обработку текста с созданием и уничтожением экземпляра
класса TRegExp или TRegExpr. Скорость работы компонента TRegExpr (Андрея Сорокина) оказалась " в 10 раз выше.
Можно сделать такой вывод, что при использовании VBScript RegExp от фирмы Microsoft
скорость сильно зависит от времени загрузки ActiveX объекта RegExp.
Скорость же работы алгоритма поиска и замены от фирмы Microsoft реализован лучше.
Несмотря на результат этого сравнения, TRegExpr(Андрея Сорокина) более удобен чем VBScript RegExp от фирмы Microsoft в том смысле, что не требуется dll и для простых проверок ввода он идеален.
Скачать пример к статье MSRegExp.zip (9.5 K)
Ссылки по теме:
[ActiveX, ActiveForm] [Регулярные выражения]
Обсуждение материала [ 09-11-2012 01:47 ] 7 сообщений |