В прошлом посте я разбирался с теорией, сейчас попробую попрактиковаться в Delphi с разными примерами из разных блогов.
Элементарно
1 2 3 4 5 6 7 8 9 10 |
//uses RegularExpressions ... procedure TForm.Button1Click(Sender: TObject); var RegEx: TRegEx; begin RegEx := TRegEx.Create('Hello');// Определяем то, что ищем, собственно регулярное выражение //Далее определяем текст, в котором ищем if RegEx.IsMatch('Hello world') then Caption := 'match'; end; |
Теперь тоже самое, но с использованием метасимволов
1 2 3 4 5 6 7 8 |
procedure TForm.ButtonClick(Sender: TObject); var RegEx:TRegEx; begin RegEx := TRegEx.Create('^H[\w]+o\b'); if RegEx.IsMatch('Hello world') then form.Caption := 'match'; end; |
Что написано в последнем коде? Разберем регулярное выражение
^H говорим машине, что в начале искомого текста (рег. выражения) должна быть большая латинская H
[\w]+ эта часть означает, что далее возможны любые буквенные или цифровые символы или знак подчеркивания
o\b – эта часть говорит машине, что в конце искомого слова должен быть символ o
Регулярные выражения без создания экземпляра класса
1 2 3 4 5 6 7 |
procedure TForm.Button1Click(Sender: TObject); var RegEx:TRegEx; begin if RegEx.IsMatch('Hello world','^H[\w]+o\b')then form.Caption := 'match'; end; |
Трабл с русским языком
К сожалению, если написать аналогичную конструкцию с метасимволами на русском языке, то всё это удовольствие не сработает.
1 2 3 4 5 6 7 |
procedure TForm.ButtonClick(Sender: TObject); var RegEx:TRegEx; begin if RegEx.IsMatch('Привет мир','^П[\w]+т\b') then form.Caption := 'match'; end; |
А вот так сработает, но это частный выход, а общий – библиотека Андрея Сорокина
1 2 3 4 5 6 7 |
procedure TForm2.Button1Click(Sender: TObject); var RegEx:TRegEx; begin if RegEx.IsMatch('Привет мир','^П[A-Яа-я]') then form.Caption := 'match'; end; |
Примеры посложнее
Отлавливаем email…
1 2 3 4 5 6 7 8 |
procedure TForm2.Button1Click(Sender: TObject); var RegEx:TRegEx; begin if RegEx.IsMatch('sometext someemail12@gmail.com sometext','[\w-.]+@([\w-]+(.[\w-]+)+)') then form.Caption := 'match'; end; |
Этот пример я взял с сайта Игоря Антонова, мне он понравился, поэтому я решил его повторить, единственное, что я изменил в нем – расставил бэкслэши перед w и d. Далее, я цитирую Игоря
[\w-.]+ – эта часть описывает адрес электронной почты до знака собачка. В соответствии со стандартом, здесь могут быть любые буквы (w), цифры от 0-9 (d), знак «-» и точка. После описания символьного класса нужно поставить метасимвол «+», иначе под данную часть шаблона у тебя будут попадать одиночные символы.
@ – понятно, что e-mail адрес не может быть без значка собачки, поэтому нам необходимо его описать.
([\w\d-]+(.[\w-]+)+) – доменная часть e-mail адреса описывается в этом небольшом кусочке. Все используемые здесь метасимволы должны быть тебе уже известны, поэтому я не буду повторяться. Просто внимательней посмотри на эту часть и все станет на свои места.
Единственное, про что я тебе не рассказывал, так это про скобки. В регулярных выражениях они выполняют двойную роль – описывают группы литералов и сохраняют эту группу в специально предопределенных переменных. В данном выражении я буду сохранять отдельно имя домена и доменную зону.
Ищем http адреса
1 2 3 4 5 6 7 8 9 |
procedure TForm.Button1Click(Sender: TObject); var RegEx:TRegEx; begin if RegEx.IsMatch('http://digital-flame.ru/', '(http|ftp)://([\w\d-]+(.[\w\d-]+)+)(([\w\d-=?\./]+)+)*') then form.Caption := 'match'; end; |
Далее, также цитирую Игоря Антонова
- (http|ftp):// – опишем возможные протоколы. Любой адрес для обращения к узлу с помощью протокола http или ftp должен начинаться с http:// или ftp:// соответственно. В скобках я указываю сначала приставку http, затем вертикальную черту, которая соответствует логическому ИЛИ и уже после нее вторую возможную приставку – ftp. В итоге наш шаблон будет срабатывать как на ссылки ftp ресурсов, так и http.
- ([wd-]+(.[wd-]+)+) – вот таким образом можно описать адрес узла. Данная конструкция будет одинаково хорошо срабатывать и на адреса вида http://192.168.0.1 – т.е. IP адрес, как и на символьные адреса. Скобками группируем условия, т.к. если просто написать диапазон литералов в одном классе и поставить метасимвол +, то выражение не будет правильно работать. Ради эксперимента советую поупражняться и попробовать составить другой шаблон.
- (([wd-=?\./]+)+)* – поскольку линк может вести на какой-нибудь файл, то мы обязаны это предусмотреть. В пути могут присутствовать различные символы: «/», «?», «=» и т.д. Поскольку часть из них являются метасимволами, то мы должны их экранировать – поставив перед ними еще один слеш. Установив шаблон можно открывать наш файл, запускать перебор по строкам, получая результат поиска. Для большей информативности, я показываю количество найденных совпадений в одном из label.
Пример Влада с сайта WebDelphi
Я его немного упростил для себя, убрал опции, и мне немного непонятно было что же такое группы. У меня после повторения примера получилось так
Сделав пример, я разобрался в том, что же такое группы. Нулевая группа это все выражение в целом, далее все то, что идет в скобках. То есть в примере выше это “gmail.com” и “.com”, что соответствует частям регулярного выражения ([\w-]+(.[\w-]+)+) и (.[\w-]+)+) соответственно.
Интересно также, что код ниже отрабатывает даже если совпадений нет. В принципе он так и должен делать, просто имхо это немного выходит из логики регулярных выражений.
1 |
ListBox.Items.Add(RegEx.Replace(Memo1.Text,'B')); |
Код, который я использовал
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
procedure TForm2.Button1Click(Sender: TObject); var RegEx: TRegEx; Options: TRegExOptions; M: TMatchCollection; i,j:integer; begin //определяем необходимые опции Options := []; // Опции я так нигде и не использовал ListBox.Items.Clear; //создаем объект RegEx := TRegEx.Create(Edit.Text); //Если найдено хотя бы обно совпадение продолжаем работу if RegEx.IsMatch(Memo.Text)then begin M := RegEx.Matches(Memo.Text, Edit.Text);//получаем коллекцию совпадений for i := 0 to M.Count-1 do begin ListBox.Items.Add(M.Item[i].Value);//выводим совпадение for j := 0 to M.Item[i].Groups.Count-1 do //если в регулярном выражении есть группы ListBox.Items.Add(' Группа '+IntToStr(j)+' '+M.Item[i].Groups[j].Value) end; //Выводим результаты работы Replace ListBox.Items.Add(RegEx.Replace(Memo.Text,Evaluator)); ListBox.Items.Add(RegEx.Replace(Memo.Text,'B')); end; end; |
В принципе, в общих чертах я разобрался для себя, что такое регулярные выражения, поэтому здесь я пока остановлюсь, если данная тема понадобится в работе, всегда можно продолжить изучать нюансы и тонкости.