![]() |
Модераторы: Poseidon, Snowy, bems, MetalFan |
![]() ![]() ![]() |
|
kemiisto |
|
||||||||||||||||||||||||
![]() Дикий Кот. =^.^= ![]() ![]() ![]() ![]() Награды: 1 Профиль Группа: Участник Клуба Сообщений: 3292 Регистрация: 29.7.2007 Репутация: 16 Всего: 160 |
Вторая редакция статьи. Исправлены ошибки, синтаксис регулярных выражений описан в более распространенных терминах. Огромное спасибо source777 за помощь в подготовке статьи!
![]() Последнюю редакцию статьи всегда можно получить по ссылке. Введение Регулярные выражения (regular expressions) — современная технология поиска текстовых фрагментов в электронных документах, соответствующих определенным образцам. Правила (rules) — это новое название регулярных выражений. Именно так они именуются в последней версиии языка Perl, признанного лидера по работе со строками. Образец (pattern), задающий правило поиска, по-русски также иногда называют «шаблоном», «маской». Регулярные выражения произвели прорыв в электронной обработке текста в конце XX века. Сейчас регулярные выражения используются многими текстовыми редакторами и утилитами для поиска и изменения текста на основе выбранных правил. Многие языки программирования уже поддерживают регулярные выражения для работы со строками. На моё удивление, в Delphi не оказалось встроенного модуля/компонента для работы с регулярными выражениями. Это существенное упущение разработчиков Delphi. Однако, как известно, свято место пусто не бывает! Итак, знакомьтесь, TRegExpr — класс для работы с регулярными выражениями в Delphi. Берём с официального сайта архив с модулем и примерами. Составные части регулярных выражений
Любой символ совпадает с самим собой (если только он не относится к метасимволам). Любая последовательность символов совпадает с такой же во входной строке. Чтобы представить метасимволы ., - [ ] и другие в регулярных выражениях без интерпретации, то есть, в качестве простых (не специальных) символов необходимо предварить их обратной косой чертой: \. Этот приём называется защитой метасимволов. Например, чтобы представить сам символ «точка» (просто точка, и ничего более), надо написать \. (обратная косая черта, а за ней - точка). Сам метасимвол \ тоже может быть защищен, то есть представлен как \\ (две обратных косых черты), и тогда интерпретатор регулярных выражений воспримет его как простой символ обратной косой черты \. Также можно использовать escape-последовательности, например:
Символьные классы Символьный класс — просто конечный набор символов. Он ограничивается квадратными скобками и содержит перечисление символов, которые можно вместо него подставить. Заменяется он всего на один символ, входящий в это перечисление. Примеры:
Стандартные символьные классы ![]() Фиксирующие директивы Фиксирующие директивы — это символы, которые привязывают правило к некоторому признаку. Например, к концу или началу строки. Наиболее часто используемые:
Квантификаторы Показывают, сколько раз может повторяться предыдущий символ (символьный класс, альтернатива и т.д.) Ограничиваются парой фигурных скобок. Примеры:
Квантификаторы
Короткие записи популярных квантификаторов ![]() Жадность Речь пойдёт о жадности среди квантификаторов. квантификаторам в регулярных выражениях соответствует максимально длинная строка из возможных (они являются «жадными», greedy). Это может оказаться значительной проблемой. Например, часто ожидают, что выражение <.*> найдёт в тексте теги HTML. Однако этому выражению соответствует целиком строка <p><b>Википедия</b> — свободная энциклопедия, в которой <i>каждый</i> может изменить или дополнить любую статью</p> Эту проблему можно решить двумя способами. Первый состоит в том, что в регулярном выражении учитываются символы, не соответствующие желаемому образцу ([^>]* для вышеописанного случая). Второй заключается в определении квантификатора как "нежадного" ("ленивого", lazy), добавив после него знак вопроса. Например, выражению <.*?> соответствует не вся показанная выше строка, а отдельные теги (выделены цветом): <p><b>Википедия</b> — свободная энциклопедия, в которой <i>каждый</i> может изменить или дополнить любую статью</p> "Жадные" варианты квантификаторов пытаются захватить как можно большую часть входного текста, в то время как "не жадные" - как можно меньшую. Например, 'b+' как и 'b*' примененные к входной строке 'abbbbc' найдут 'bbbb', в то время как 'b+?' найдет только 'b', а 'b*?' - вообще - пустую строку; 'b{2,3}?' найдет 'bb', в то время как 'b{2,3}' найдет 'bbb'. Альтернативы Нужны, когда необходимо объединить несколько правил в одно. При этом совпадение засчитывается, когда есть совпадение хотя бы с одним правилом. Желательно альтернативы заключать внутрь группировки (круглые скобки). Правила, входящие в вариант, разделяются | (вертикальной чертой). Примеры:
В данном примере продемонстрирована альтернатива в группировке. В принципе альтернатива может существовать и вне группировки, но так возникает больше ошибок. Группировки Используются, когда необходимо обрабатывать результат частями. Например, при обработке ссылок в HTML-документе удобно отдельно обрабатывать текст ссылки и URL. Группировки заключаются в круглые скобки. Модификаторы Модификаторы предназначены для изменения поведения правила. Назначение и примеры - смотри в справке. Использование в Delphi Рассмотрим несколько примеров использования регулярных выражений в Delphi. Пример использования Использовать регулярные выражения в Delphi просто.
Результат работы программы: ![]() Пример использования вариантов и подвыражений
Регулярное выражение для этого случая будет выглядеть несколько сложнее: (\d+)([.,])(\d+), т.е. содержать соотв. подвыражения (целая и дробная части) и вариант (в качестве разделителя может выступать как точка, так и запятая), который также представляет собой подвыражение. Выражение, соотв. всему регулярному выражению по-прежнему находится в Match[0], а вот Match[i] содержит i-ую группировку. Также обратите своё внимание на достаточно интересную функцию
которая возвращает ATemplate, в котором все '$&' и '$0' заменены на найденное регулярное выражение, а '$n' на n-ое подвыражение. Например, оператор
добавленный в предыдущий пример, вывел бы исходное число. Пример анализа текста Давайте напишем простенький анализатор текста. На это раз сделаем GUI-приложение. На форме расположим один экземпляр TButton, один экземпляр TMemo и пять экземпляров TLabel. ![]() При нажатии на кнопку, реализуем показ диалога выбора текстового файла и загрузку его в Memo1.
Теперь давайте реализуем сбор статистики по мере изменения текста в Memo1:
Во-первых, остановимся на подсчёте количества символов, исключая пробельные. Здесь был использован метод
заменяющий в AInputStr все вхождения регулярного выражения на AreplaceStr. Вычисляя сумму длин полученных таким образом строк, получим искомую величину. Теперь взглянем на подсчёт количества предложений в нашем примере. Ответом на вопрос «Что надо найти?», будет, скорее всего, «Количество точек, знаков восклицания и знаков вопроса, стоящих в конце слова или строки.» Кроме того, следует учитывать возможность наличия неединичных знаков препинания (…, !?). Составляем регулярное выражение '[.!?]+(\s|$)', и собственно всё! Задача решена! При подсчёте количества слов можно, например, использовать регулярное выражение вида '\s*[^\s.-]+-?[^\s.-]*. Слово может следовать за пробелом, а может и нет (если стоит в начале текста). Поэтому вначале нашеговыражения стоит \s*. Собственно слово (написанное без орфографических ошибок) — последовательность непробельных символов. То есть мы могли бы записать регулярное вражение так: '\s*[\S]'. Но под такой шаблон попадут и некоторые другие символы и их последовательности, которые врядли можно назвать словами — многоточие, тире. Чтобы исправить ситуацию мы пишем '\s*[^\s.-]'. Ну и, наконец, необходимо учесть наличие слов, которые пишутся через дефис и получим '\s*[^\s.-]+-?[^\s.-]*. Важно понимать, что основное преимущество при использовании регулярных выражений заключается в экономии времени! Вам необходимо лишь задаться вопросом «Что надо найти?» и составить регулярное выражение, которое является ответом на этот вопрос, а не разрабатывать «с нуля» алгоритм поиска. Успехов! ![]() Архив с примерами Статья в PDF P.S. Для тестирования регулярных выражений можнов воспользоваться инструментом RegExp Studio, взять который можно тут. Это сообщение отредактировал(а) kemiisto - 7.2.2009, 20:37 -------------------- |
||||||||||||||||||||||||
|
|||||||||||||||||||||||||
MetalFan |
|
|||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 62 Всего: 128 |
а если многоточие? ) ничего так статья, для начинающих самое то! кстати, к самим RegExpr идет очень подробный и познавательный хелп на русском. многие ньансы там освещены. Это сообщение отредактировал(а) MetalFan - 25.5.2008, 11:01 -------------------- There are always someone smarter than you... |
|||
|
||||
kemiisto |
|
|||
![]() Дикий Кот. =^.^= ![]() ![]() ![]() ![]() Награды: 1 Профиль Группа: Участник Клуба Сообщений: 3292 Регистрация: 29.7.2007 Репутация: 16 Всего: 160 |
MetalFan, согласен! Просто первое, что пришло на ум было '\.|\?|!' Спасибо! Рад стараться! ![]() -------------------- |
|||
|
||||
THandle |
|
|||
![]() Хранитель Клуба ![]() Награды: 1 Профиль Группа: Админ Сообщений: 3639 Регистрация: 31.7.2007 Где: Moscow, Dubai Репутация: 65 Всего: 372 |
kemiisto, хорошая статья, спасибо, начну изучать. Все понятно и хорошо написано
![]() |
|||
|
||||
lukas |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 771 Регистрация: 23.2.2007 Репутация: 3 Всего: 15 |
Да регулярные выражение это крутая вещь... где я их только не использую... а на счет скорости работы функций из этого модуля... Все из них при обращении создают новый объект TRegExpr и исбавляются от него в конце, что и замедляет выполнение функции при большом кол-во использований...
-------------------- http://code.google.com/p/orionphp/ - opensource скриптовой язык Orion (аналог PHP) для freepascal/delphi. |
|||
|
||||
Poseidon |
|
|||
![]() Delphi developer ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 5273 Регистрация: 4.2.2005 Где: Гомель, Беларусь Репутация: 53 Всего: 133 |
-------------------- Если хочешь, что бы что-то работало - используй написанное, если хочешь что-то понять - пиши сам... |
|||
|
||||
lukas |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 771 Регистрация: 23.2.2007 Репутация: 3 Всего: 15 |
На этой странице проблемы с кодировкой, пробовал в 3х браузерах... скорее вот из за этого...
-------------------- http://code.google.com/p/orionphp/ - opensource скриптовой язык Orion (аналог PHP) для freepascal/delphi. |
|||
|
||||
Poseidon |
|
|||
![]() Delphi developer ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 5273 Регистрация: 4.2.2005 Где: Гомель, Беларусь Репутация: 53 Всего: 133 |
IE7 при установке в ручную "Кириллица (Windows)" нормально отображает
-------------------- Если хочешь, что бы что-то работало - используй написанное, если хочешь что-то понять - пиши сам... |
|||
|
||||
source777 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 4 Всего: 56 |
Лучше уж заменить эту конструкцию на '[.!?](\s|$)', так будет намного точнее... Добавлено через 3 минуты и 42 секунды Вообще, я мельком только статью просмотрел, но даже при этом бросилось в глаза непонимание автором оператора | , очень во многих местах он используется абсолютно не к месту... -------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
|||
|
||||
Foux |
|
|||
Новичок Профиль Группа: Участник Сообщений: 5 Регистрация: 27.5.2008 Репутация: нет Всего: нет |
Здесь рассмотрены примеры поиска конкретных символов,
но как получить символы находящиеся между определенных символов, например содержимое HTML тэга? |
|||
|
||||
source777 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 4 Всего: 56 |
'<a\s+href=(.*?)\s.*?>(.*?)</a>' В итоге ссылка будет в RegExp.Match[1], а текст ссылки в RegExp.Match[2]. -------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
|||
|
||||
kemiisto |
|
||||
![]() Дикий Кот. =^.^= ![]() ![]() ![]() ![]() Награды: 1 Профиль Группа: Участник Клуба Сообщений: 3292 Регистрация: 29.7.2007 Репутация: 16 Всего: 160 |
source777, спасибо за feedback! Но, буду защищаться!
Хм... За прошедшее время пролистал несколько книг по регулярным выражениям. Вот что, к примеру, пишет Джеффри Фридл
Я и не путаю. Мне пришло в голову записать '\.|\?|!', Вам - '[.!?]'. Это фактически одно и тоже. Где же тут, простите, "непонимание"? Да и, вообще, "к месту/ не к месту" определяет, по-моему, автор.
Да, лучше. Но я же чётко написал: Добавлено через 2 минуты и 55 секунд Народ, а кто тег " Регульрные" добавил? Исправить можно? -------------------- |
||||
|
|||||
source777 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 4 Всего: 56 |
Тихо, тихо. Во-первых, это только логически одно и то же, да и то далеко невсегда. Например, '\w+|[а-яА-Я]+' совсем не то же самое, что '[\wа-яА-Я]+', вот тебе и непонимание, а говорил, что не путаешь... А во-вторых, это дополнение твоей заметки, а не перечёркивание её целиком, имхо, с твоей стороны вместо того, чтобы гордиться тем, что тебе пришло на ум по крайней мере, стоило бы внести изменения на более правильные варианты. -------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
|||
|
||||
Matematik |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1027 Регистрация: 11.3.2006 Репутация: 17 Всего: 50 |
Еще есть TPerlRegEx http://www.regular-expressions.info/delphi.html
В тяжелых случаях работает быстрее чем TRegExpr |
|||
|
||||
Akella |
|
|||
![]() Творец ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 18485 Регистрация: 14.5.2003 Где: Корусант Репутация: 36 Всего: 329 |
Matematik,
|
|||
|
||||
![]() ![]() ![]() |
Правила форума "Delphi: Общие вопросы" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |