Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нем неправильно. Необходимо обновить браузер или попробовать использовать другой.
Обсуждение уроков по работе с Регулярными Выражениями (RegExp)
AZJIO
Хорошие замечания!
Но я не могу вносить изменения в ту тему :wall_brake:
Модераторы/Администраторы пожалуйста подправьте здесь Урок 2 / Метасимволы.Дополнительные
[box title=TitleBox]"\b" - граница слова (например, буква "b" и "g" в слове "boring" находятся на границе, а буквы "orin" нет). Работает только для букв английского алфавита![/box]
[box title=TitleBox]"\W" - не символ буквы "слова" - все что не попало в "(a-zA-Z0-9_)", т.е. русские буквы, символы пробелов, символы пунктуации и пр.[/box]
В новой справке добавились метасимволы:
(?J) - allow duplicate names (разрешает дубликаты/двойные названия).
\K - reset start of match.
\G - first matching position in subject
\N - [^\n] Любой символ, который не символ перехода на новую строку (не @LF). Не работает в 3.3.6.1
\R - [\n\f\r\v] Chr(10), Chr(11), Chr(12), Chr(13) любой из символов переноса строки
Некоторые ((?J), \K, \G) не понял пока для чего...
Кроме того для \s и для классов типа [[:upper:]] сделал поправки указав конкретные диапазоны символов.
Вот тестовый скрипт для определения захвата символов
Код:
$invert=0 ; инвертировать вывод
$Number=1 ; вывод в цифре или в символах
$mask='[[:space:]]' ; выражение для поиска
$sep=',' ; разделитель
$a=''
For $i = 0 To 255
$b=StringRegExpReplace(Chr($i), $mask, '\0')
If $invert Then
If Not @extended Then
If $Number Then
$a&=Asc($b) &$sep
Else
$a&=$b &$sep
EndIf
EndIf
Else
If @extended Then
If $Number Then
$a&=Asc($b) &$sep
Else
$a&=$b &$sep
EndIf
EndIf
EndIf
Next
$a=StringTrimRight($a, 1)
; $z=StringSplit($a, $sep, 1) ; с проверкой целостности диапазона
; For $i = 2 To $z[0]
; If Number($z[$i])<>Number($z[$i-1])+1 Then MsgBox(0, 'Сообщение', 'Ошибка последовательности n='&$z[$i] &@CRLF&$z[0])
; Next
MsgBox(0, '', $a)
Python и языки .NET позволяют сохранить текст, совпавший с круг
лыми скобками, под заданным именем. В Python используется син
таксис (?Р<имя>…), а в языках .NET – синтаксис (?<имя>…) (лично
мне этот вариант нравится больше).
В 3.3.6.1 версии возможности именовать подшаблоны я не видел или плохо смотрел.
А флаг (?J) позволяет использовать одно имя для разных шаблонов.
В Python и .NET (но не в PHP) допускается многократное использова
ние имен в выражениях. Например, если код междугородной связи
в телефонном номере записывается в виде ‘(###)’ или ‘###-’, для
его поиска можно воспользоваться следующим выражением (исполь
зован синтаксис .NET): …(?:\((?<Area>\d\d\d)\)|(?<Area>\d\d\d)-)… Ка
кая бы из альтернатив ни совпала, код из трех цифр будет ассоцииро
ван с именем Area.
Метасимвол \G впервые появился в Perl и предназначался для проведе
ния глобального поиска с модификатором /g . Он совпадает с по
зицией, в которой завершилось предыдущее совпадение. При первой
итерации \G совпадает только в начале строки, как и метасимвол \A.
Если попытка поиска завершилась неудачей, позиция \G возвращается
в начало строки. Таким образом, при многократном применении регу
лярного выражения (как при использовании команды s/…/…/g или дру
гих средств глобального поиска) неудача при очередном поиске приво
дит к сбросу позиции \G для применения следующего выражения.
Обычно в результате неудачной попытки поиска m/…/g позиция pos воз
вращается в начало целевого текста. Но если к модификатору /g доба
вить модификатор /c, неудача не будет приводить к сбросу начальной
позиции поиска.
может и существует но не 10, возможно 99, потому что трёхзначные числа /001 это уже восьмеричный код. НО это для ссылок внутри регулярного выражения, хотя можно и так \{200} в случае конфликта. Вот пример с 5460 ссылкой, странное число, может ограничение по длине строки.
Я тоже хотел свой вариант написать, но вдохновения нет. Вот некоторые идеи regexp.7z.
Недостатки в твоём варианте:
1. Имена разделов лучше назвать по их содержанию, например не "Урок 1. Введение", а к примеру "Параметры функций SRE". Потом "Описание метасимволов". Так проще ориентироваться и сразу выбирать нужный раздел для чтения.
2. Флаги 1 и 2 предназначены не просто найти первое вхождение, а сделать последовательный/пошаговый поиск в цикле.
3. Примеры некоторые либо нереальные, либо ...
"удав 11 человек 2 крокодил 4" - человек в перечислении зверей, да ещё на втором месте.
"Берлин Германия|Афины Греция|Москва Россия" - почему Россия последняя.
"Кто убил Лору Палмер? Варианты ответа: а)бомж. б)китаец. в)Девид Линч. г)отец" - не позитивный пример, как будто жизнь построена на убийствах, а дальше перечисление, обзываем человека бомжом, далее националистический выбор... сплошной непозитив.
может и существует но не 10, возможно 99, потому что трёхзначные числа /001 это уже восьмеричный код. НО это для ссылок внутри регулярного выражения, хотя можно и так \{200} в случае конфликта. Вот пример с 5460 ссылкой, странное число, может ограничение по длине строки.
Я так далеко не закапывался и даже не помню откуда взялись слова про ограничение , но да, получается что можно писать $1... и до упора, а вот со слэшем \1 возможны варианты:
[box title=opennet.ru]
Можно использовать любое количество скобок. Если имеется более 9 подстрок, переменные $10, $11, ... будут ссылаться на соответствующую подстроку. В шаблоне \10, \11 и т.д. ссылаются на уже сопоставленные подстроки, если их уже было столько до этой обратной ссылки. В противном случае (для обратной совместимости) \10 совпадает с \010, или символом забоя, а \11 совпадает с \011, символом табуляции. И так далее. (Последовательности от \1 до \9 всегда рассматриваются как обратные ссылки.)[/box]
Но не суть, если человеку понадобится больше 10 обратных ссылок, то он делает что-то не так или он сам разберется как ему с ними работать, а 10 - обычному пользователь за глаза хватит.
Если модераторы посчитают данное изменение важным, то вот текст на замену в первом посте обучения (сам я ничего менять не могу :D):
[box title=старый]Кроме обычных замен текстом replace поддерживает обратные ссылки (back-reference), то есть может манипулировать найденными по шаблону элементами. Существует ограничение на количество ссылок - максимум 10, обозначение ссылок "$0-$9" или "\0 - \9", обратная ссылка "\0" или "$0" включает в себя полное совпадение с шаблоном[/box]
[box title=новый]Кроме обычных замен текстом replace поддерживает обратные ссылки (back-reference), то есть может манипулировать найденными по шаблону элементами. Обозначение ссылок может записываться как "$0", "$1", "$2" ... или "\0", "\1", "\2" ..., обратная ссылка "\0" или "$0" включает в себя полное совпадение с шаблоном[/box]
Я тоже хотел свой вариант написать, но вдохновения нет. Вот некоторые идеи regexp.7z.Недостатки в твоём варианте:1. Имена разделов лучше назвать по их содержанию, например не "Урок 1. Введение", а к примеру "Параметры функций SRE". Потом "Описание метасимволов". Так проще ориентироваться и сразу выбирать нужный раздел для чтения.2. Флаги 1 и 2 предназначены не просто найти первое вхождение, а сделать последовательный/пошаговый поиск в цикле.3. Примеры некоторые либо нереальные, либо ..."удав 11 человек 2 крокодил 4" - человек в перечислении зверей, да ещё на втором месте."Берлин Германия|Афины Греция|Москва Россия" - почему Россия последняя."Кто убил Лору Палмер? Варианты ответа: а)бомж. б)китаец. в)Девид Линч. г)отец" - не позитивный пример, как будто жизнь построена на убийствах, а дальше перечисление, обзываем человека бомжом, далее националистический выбор... сплошной непозитив.
Считаю что не нужно отпугивать новичков непонятными сокращениями и словами сразу с оглавления. Что за SRE, что за метасимволы?
Мое обучение сделано пошагово, чтобы новичок сначала понял для чего это вообще нужно, как с этим работать, что такое шаблон и из чего он состоит, а дальше уже идет кунг-фу для тех кто осилил начало
Да вдохновение это сложно, я вот с примерами дольше всего мучился, поэтому некоторые из них могут быть слегка натянутыми. :whistle: - человек тоже животное, порядок тут не важен как и в географическом тексте, а пример про "Твин Пикс" по-моему очень даже позитивный.
В твоём regexp_error.htm:
"[\w] \w Заключение одного символа в символьный класс. В символьный класс имеет смысл заключать 2 и более символов / метасимволов." и пара других примеров - это скорее не ошибки, а недостаток оптимизации/упрощения. Вот кстати можно сделать классный урок или отдельную тему по оптимизации регулярок, но я уже за это точно не возьмусь.
SRE - это какое-то новое сокращение, которое даже не гуглится ;) , лучше уж оставить RegEx
PS: В твоих файлах нашел пару опечаток: "SPE" в regexp_introduction.htm, "Запсись короче и скорость выше. Или 8 символов проверять или 6, разница есть?" в regexp_error.htm
Ну что такое SRE можно понять даже по контексту, оно используется в официальной справке и на форуме при общении на офсайте используют, когда тот же новичок будет натыкаться по 10 раз в одном предложении на "регулярные выражения" у него уже тошнить от этого начнёт, думал про сокращение рег.выр. но даже это длинно при 200 кратном использовании, а при опускании существительных текст будет читаться тоже уродливо. На счёт метасимвол, ну в Google введи, любая статья использует этот термин, мне как то интуитивно он был понятен, символы использующиеся не в буквальном смысле, тоже что сказать спец-символы, но метасимвол -устоявшееся понятие.
так можно сказать про большинство ошибок, которые там упомянуты. Кстати 5 ошибок из списка мои (я их допускал), остальные найдены у других.
Может статья не должна быть заблокирована от правки? Это же нормально чтобы в любой момент можно было улучшить. Я практически с каждой версией утилиты RegExp делаю правку в сопутствующей справке, каждый раз находя ошибки, последнее удалил строку "{,n} повторить предыдущий символ от 0 до n раз", где то же я её скопировал, но недавно при тесте не мог заставить её работать.
На счёт упора на новичка, думаю лучше ориентироваться на умного новичка, для которого не нужна нянька, чтобы разжёвывать до смешного. Думаю такой подход будет полезен и продвинутому, чтобы заглядывать как в справочник. Подход один раз показал как работает один метасивол диапазона, остальные нет смысла показывать потому что они работают по тому же принципу,только захват разный.
regexp.7z - обновил, добавлено одно упражнение и продолжение темы "Группы".
Большое спасибо и огромное уважение всем кто участвовал в написании этих Уроков.
Весь мозг вывернул пока дочитал до конца и понял (ну как мне кажется) все моменты. :wacko:
Обнаруженные недочеты:
01.
Урок 1. -> StringRegExp -> flag -> flag = 4 -> Код
Нужно применить Tidy.
02.
Урок 2 -> Элементы шаблона -> (Спойлер)Метасимволы. -> описание "(?: )"
Не описан один момент:
Код:
#include <Array.au3>
$sText = '1234'
$sPattern = '(?:\d+)4' ; Выводится весь шаблон, даже группа БЕЗ захвата, т.к. групп С захватом нет
_ArrayDisplay(StringRegExp($sText, $sPattern, 3))
$sPattern = '(?:\d+)(4)' ; Выводится только группа с захватом
_ArrayDisplay(StringRegExp($sText, $sPattern, 3))
03.
Урок 2 -> Элементы шаблона -> (Спойлер) Метасимволы. Дополнительные -> описание символа "\n" и "\w"
В коде примера не используется ".", таким образом флаг "(?s)" лишний.
04.
Урок 2 -> Элементы шаблона -> (Спойлер) Метасимволы. Квантификаторы
Спойлер не дописан.
05.
Урок 3. -> Условия просмотра вперед и назад... -> (Спойлер) Просмотр вперед и назад -> описание "(?=pattern)"
Расшифровка шаблона не совпадает с примером.
06.
Урок 3. -> Условия просмотра вперед и назад... -> (Спойлер) Просмотр вперед и назад -> описание "(?"
Опечатка в тексте:
"(?" необходимо заменить на "(?<!pattern)"
Урок 4 -> Выбор инструмента -> (Спойлер) Инструменты -> Извлечение информации из текста
Для извлечения одного определенного элемента, как правило уникального, (например, название трека из ID3-Tag для mp3-файла, или все теги из файла, но одной строкой) из всего текста используется StringRegExpReplace с использованием обратных ссылок ...
Урок 2 -> Элементы шаблона -> (Спойлер)Метасимволы. Дополнительные -> описание "\z" и "\Z"
"\z" - совпадает с концом строки, не зависит от флага "(?m)" (будет рассмотрен ниже).
"\Z" - совпадает с концом строки или позицией до последнего символа новой строки, не зависит от флага "(?m)" (будет рассмотрен ниже).
Заменить на:
"\z" - совпадает с концом текста, не зависит от флага "(?m)" и поэтому может встретится только 1 раз (будет рассмотрен ниже).
"\Z" - совпадает с концом текста или позицией перед последним символом @LF, не зависит от флага "(?m)" и поэтому может встретится только 1 раз (будет рассмотрен ниже).
04.
Урок 3. -> Условия просмотра вперед и назад... -> (Спойлер) Просмотр вперед и назад -> описание "(?=pattern)", "(?!pattern)", "(?<=pattern)"
Слово "pattern" в названии данных флагов сбивает с толку, потому как весь шаблон принято называть также.
Есть один неприятный момент - при использовании условных масок (даже при использовании групп без захвата) в вывод попадает все что лежит за условной подмаской и записано в шаблоне, во всяком случае у меня не получилось иначе.
...
Если кто-то найдет решение - прошу написать об этом, но ИМХО тут дело не в условных масках, а в самом механизме RegExp.
; Пример (шаблон типа "(?(condition)yes-pattern|no-pattern)") из многострочного текста для стран, начинающихся на букву "Р" выводит всю строку, а для других только название страны:
#include <Array.au3>
Local $sPattern[3], $aResult[5][3]
$sText = 'Страна: Китай; Столица: Пекин; Население: 1347млн.' & @LF & _
'Страна: Россия; Столица: Москва; Население: 144млн.' & @LF & _
'Страна: США; Столица: Вашингтон; Население: 313млн.' & @LF & _
'Страна: Румыния; Столица: Бухарест; Население: 21млн.'
$sPattern[0] = 'Страна:\s(?(?=Р).+|[^;]+)'
$sPattern[1] = 'Страна:\s((?(?=Р).+|[^;]+))'
$sPattern[2] = '(?<=Страна:\s)(?(?=Р).+|[^;]+)'
For $i = 0 To 2
$aOutput = StringRegExp($sText, $sPattern[$i], 3)
For $j = 0 To UBound($aOutput) - 1
$aResult[$j][$i] = $aOutput[$j]
Next
Next
_ArrayDisplay($aResult, 'Результаты:', '', 64, Default, 'Исходный вариант: $sPattern[0]|Вариант 1: $sPattern[1]|Альтернативный вариант: $sPattern[2]')
Код 2:
Код:
; Второй пример (шаблон типа "(?(condition)yes-pattern)") из текста выводит слова, которые начинаются с буквы "т":
#include <Array.au3>
Local $sPattern[3], $aResult[10][3]
$sText = 'текст окно тело горн овес порт отвертка кино тоник'
$sPattern[0] = '(?:\s|^)(?(?=т)\S+)'
$sPattern[1] = '(?:\s|^)((?:(?=т)\S+))'
$sPattern[2] = '(?<=\s|^)(?:(?=т)\S+)'
For $i = 0 To 2
$aOutput = StringRegExp($sText, $sPattern[$i], 3)
For $j = 0 To UBound($aOutput) - 1
$aResult[$j][$i] = '[' & $aOutput[$j] & ']'
Next
Next
_ArrayDisplay($aResult, 'Результаты:', '', 64, Default, 'Исходный вариант: $sPattern[0]|Вариант 1: $sPattern[1]|Альтернативный вариант: $sPattern[2]')
Из своих наблюдений:
- Условные подмаски не являются группами назначенными для захвата, т.е. их нужно рассматривать как "(?:...)".