Что нового

Обсуждение уроков по работе с Регулярными Выражениями (RegExp)

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
AZJIO
Хорошие замечания!
Но я не могу вносить изменения в ту тему :wall_brake:

Модераторы/Администраторы пожалуйста подправьте здесь Урок 2 / Метасимволы.Дополнительные
[box title=TitleBox]"\b" - граница слова (например, буква "b" и "g" в слове "boring" находятся на границе, а буквы "orin" нет). Работает только для букв английского алфавита![/box]
[box title=TitleBox]"\W" - не символ буквы "слова" - все что не попало в "(a-zA-Z0-9_)", т.е. русские буквы, символы пробелов, символы пунктуации и пр.[/box]
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Redline
Поправил.
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
AZJIO
Укажи какие теги использовать для заголовков тем/подтем (h1/h2 подойдут?) и спойлеров.
Лучше в личку.
 

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
В новой справке добавились метасимволы:
(?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)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
AZJIO [?]
Некоторые ((?J), \K, \G) не понял пока для чего...
\G это вроде обратное от \g, что означает глобальный поиск. В данном случае \G предотвращает глобальное совпадение, т.е ищет только первое.
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
AZJIO [?]
(?J) - allow duplicate names (разрешает дубликаты/двойные названия).
Фридл
Python и языки .NET позволяют сохранить текст, совпавший с круг
лыми скобками, под заданным именем. В Python используется син
таксис (?Р<имя>…), а в языках .NET – синтаксис (?<имя>…) (лично
мне этот вариант нравится больше).
В 3.3.6.1 версии возможности именовать подшаблоны я не видел или плохо смотрел.
А флаг (?J) позволяет использовать одно имя для разных шаблонов.

В Python и .NET (но не в PHP) допускается многократное использова
ние имен в выражениях. Например, если код междугородной связи
в телефонном номере записывается в виде ‘(###)’ или ‘###-’, для
его поиска можно воспользоваться следующим выражением (исполь
зован синтаксис .NET): …(?:\((?<Area>\d\d\d)\)|(?<Area>\d\d\d)-)… Ка
кая бы из альтернатив ни совпала, код из трех цифр будет ассоцииро
ван с именем Area.

\G - first matching position in subject
Фридл
Метасимвол \G впервые появился в Perl и предназначался для проведе
ния глобального поиска с модификатором /g . Он совпадает с по
зицией, в которой завершилось предыдущее совпадение. При первой
итерации \G совпадает только в начале строки, как и метасимвол \A.

Если попытка поиска завершилась неудачей, позиция \G возвращается
в начало строки. Таким образом, при многократном применении регу
лярного выражения (как при использовании команды s/…/…/g или дру
гих средств глобального поиска) неудача при очередном поиске приво
дит к сбросу позиции \G для применения следующего выражения.
Тут непонятно, но кажется этот метасимвол позволяет сохранить позицию от предыдущего поиска при глобальном поиске :wacko:

Здесь могу ошибаться, но вроде оно:
Обычно в результате неудачной попытки поиска m/…/g позиция pos воз
вращается в начало целевого текста. Но если к модификатору /g доба
вить модификатор /c, неудача не будет приводить к сбросу начальной
позиции поиска.
Похоже в AutoIt при глобальном поиске этот модификатор /c включен сразу и через \K его можно отключать.

Получается это все какие-то экзотические возможности, а вот \R и \N вполне можно употреблять.
 

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
Redline
Существует ограничение на количество ссылок - максимум 10, обозначение ссылок "$0-$9" или "\0 - \9"
может и существует но не 10, возможно 99, потому что трёхзначные числа /001 это уже восьмеричный код. НО это для ссылок внутри регулярного выражения, хотя можно и так \{200} в случае конфликта. Вот пример с 5460 ссылкой, странное число, может ограничение по длине строки.
Код:
$sString = ''
$sPattern = ''
$iEnd = 5460
For $i = 1 To $iEnd
	$sString &= $i & '|'
	$sPattern &= '(\d+\|)'
Next
; MsgBox(0, 'Сообщение', $sString)
; MsgBox(0, 'Сообщение', $sPattern)

$aRes=StringRegExpReplace($sString, $sPattern, '\' & $iEnd)
MsgBox(0, 'Сообщение', $aRes)


Я тоже хотел свой вариант написать, но вдохновения нет. Вот некоторые идеи regexp.7z.
Недостатки в твоём варианте:
1. Имена разделов лучше назвать по их содержанию, например не "Урок 1. Введение", а к примеру "Параметры функций SRE". Потом "Описание метасимволов". Так проще ориентироваться и сразу выбирать нужный раздел для чтения.
2. Флаги 1 и 2 предназначены не просто найти первое вхождение, а сделать последовательный/пошаговый поиск в цикле.
3. Примеры некоторые либо нереальные, либо ...
"удав 11 человек 2 крокодил 4" - человек в перечислении зверей, да ещё на втором месте.
"Берлин Германия|Афины Греция|Москва Россия" - почему Россия последняя.
"Кто убил Лору Палмер? Варианты ответа: а)бомж. б)китаец. в)Девид Линч. г)отец" - не позитивный пример, как будто жизнь построена на убийствах, а дальше перечисление, обзываем человека бомжом, далее националистический выбор... сплошной непозитив.
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
AZJIO [?]
может и существует но не 10, возможно 99, потому что трёхзначные числа /001 это уже восьмеричный код. НО это для ссылок внутри регулярного выражения, хотя можно и так \{200} в случае конфликта. Вот пример с 5460 ссылкой, странное число, может ограничение по длине строки.
Я так далеко не закапывался и даже не помню откуда взялись слова про ограничение :smile: , но да, получается что можно писать $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, что за метасимволы?
Мое обучение сделано пошагово, чтобы новичок сначала понял для чего это вообще нужно, как с этим работать, что такое шаблон и из чего он состоит, а дальше уже идет кунг-фу для тех кто осилил начало :smile:

Да вдохновение это сложно, я вот с примерами дольше всего мучился, поэтому некоторые из них могут быть слегка натянутыми. :whistle: - человек тоже животное, порядок тут не важен как и в географическом тексте, а пример про "Твин Пикс" по-моему очень даже позитивный.

В твоём regexp_error.htm:
"[\w] \w Заключение одного символа в символьный класс. В символьный класс имеет смысл заключать 2 и более символов / метасимволов." и пара других примеров - это скорее не ошибки, а недостаток оптимизации/упрощения. Вот кстати можно сделать классный урок или отдельную тему по оптимизации регулярок, но я уже за это точно не возьмусь.

SRE - это какое-то новое сокращение, которое даже не гуглится ;) , лучше уж оставить RegEx

PS: В твоих файлах нашел пару опечаток: "SPE" в regexp_introduction.htm, "Запсись короче и скорость выше. Или 8 символов проверять или 6, разница есть?" в regexp_error.htm
 

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
Redline
Вот ссылка с офсайта, текст на английском, но из этого можно было бы сделать уроки. Взять как основу.

Считаю что не нужно отпугивать новичков непонятными сокращениями и словами сразу с оглавления. Что за SRE, что за метасимволы?
Ну что такое SRE можно понять даже по контексту, оно используется в официальной справке и на форуме при общении на офсайте используют, когда тот же новичок будет натыкаться по 10 раз в одном предложении на "регулярные выражения" у него уже тошнить от этого начнёт, думал про сокращение рег.выр. но даже это длинно при 200 кратном использовании, а при опускании существительных текст будет читаться тоже уродливо. На счёт метасимвол, ну в Google введи, любая статья использует этот термин, мне как то интуитивно он был понятен, символы использующиеся не в буквальном смысле, тоже что сказать спец-символы, но метасимвол -устоявшееся понятие.

В твоих файлах нашел пару опечаток
опечатки потом проверю через какую нибудь программу с проверкой орфографии, тот же Word.

очень даже позитивный
мне нравятся профессиональные программы, в которых не пропагандируется ущемление чьих либо прав, традиций, вероисповедания. Здесь подобный случай.

это скорее не ошибки, а недостаток оптимизации/упрощения
так можно сказать про большинство ошибок, которые там упомянуты. Кстати 5 ошибок из списка мои (я их допускал), остальные найдены у других.

Может статья не должна быть заблокирована от правки? Это же нормально чтобы в любой момент можно было улучшить. Я практически с каждой версией утилиты RegExp делаю правку в сопутствующей справке, каждый раз находя ошибки, последнее удалил строку "{,n} повторить предыдущий символ от 0 до n раз", где то же я её скопировал, но недавно при тесте не мог заставить её работать.

На счёт упора на новичка, думаю лучше ориентироваться на умного новичка, для которого не нужна нянька, чтобы разжёвывать до смешного. Думаю такой подход будет полезен и продвинутому, чтобы заглядывать как в справочник. Подход один раз показал как работает один метасивол диапазона, остальные нет смысла показывать потому что они работают по тому же принципу,только захват разный.

regexp.7z - обновил, добавлено одно упражнение и продолжение темы "Группы".
 
A

Alofa

Гость
Большое спасибо и огромное уважение всем кто участвовал в написании этих Уроков.
Весь мозг вывернул пока дочитал до конца и понял (ну как мне кажется) все моменты. :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)"
07.Урок 3. -> Условные подмаски... -> (Спойлер) Условные подмаскиОпечатка в тексте:
Второй пример (шаблон типа "(?(condition)yes-pattern)") из текста выводит слова, которые начинаются на с буквы "т":
08.Урок 4 -> Выбор инструмента -> (Спойлер) Инструменты -> Извлечение информации из текста
Для извлечения одного определенного элемента, как правило уникального, (например, название трека из ID3-Tag для mp3-файла, или все теги из файла, но одной строкой) из всего текста используется StringRegExpReplace с использованием обратных ссылок ...
Ссылка "обратных ссылок" ведет к Уроку 3, а надо к Уроку 1. -> StringRegExpReplace -> (Спойлер) дополнительные возможности - обратные ссылки
09.Урок 4 -> Практические примерыНеправильная иерархия (расстановка) спойлеров.
Спойлер "Изменение информации (замена)" расположен внутри спойлера "Извлечение информации".
10.Урок 5 -> Использование RegExp через объекты -> (Спойлер) VBScript.RegExpНеобходимо закончить BBC.
он умеет работать с [url=http://creator-lab.ucoz.ru/index/uroki_reguljarnykh_vyrazhenij_3/0-13#2"]просмотром вперед[/url]

В качестве предложения:
01.Урок 2 -> Элементы шаблона -> (Спойлер)Метасимволы. Дополнительные -> описание "\A"
"\A" - начало строки, не зависит от флага "(?m)" и поэтому может встретится только 1 раз.
Заменить на:
"\A" - начало текста, не зависит от флага "(?m)" и поэтому может встретится только 1 раз.
02.Урок 2 -> Элементы шаблона -> (Спойлер)Метасимволы. Дополнительные -> описание "\v"Из описания непонятно почему:
... вертикальная табуляция (устарела).
03.Урок 2 -> Элементы шаблона -> (Спойлер)Метасимволы. Дополнительные -> описание "\z" и "\Z"
"\z" - совпадает с концом строки, не зависит от флага "(?m)" (будет рассмотрен ниже).
"\Z" - совпадает с концом строки или позицией до последнего символа новой строки, не зависит от флага "(?m)" (будет рассмотрен ниже).
Заменить на:
"\z" - совпадает с концом текста, не зависит от флага "(?m)" и поэтому может встретится только 1 раз (будет рассмотрен ниже).
"\Z" - совпадает с концом текста или позицией перед последним символом @LF, не зависит от флага "(?m)" и поэтому может встретится только 1 раз (будет рассмотрен ниже).
04.Урок 3. -> Условия просмотра вперед и назад... -> (Спойлер) Просмотр вперед и назад -> описание "(?=pattern)", "(?!pattern)", "(?<=pattern)"Слово "pattern" в названии данных флагов сбивает с толку, потому как весь шаблон принято называть также.
05.Урок 3. -> Условные подмаски... -> (Спойлер) Условные подмаски
Код:
#include <Array.au3> 
$sText = 'Страна: Китай; Столица: Пекин; Население: 1347млн.' & @CRLF 
$sText &= 'Страна: Россия; Столица: Москва; Население: 144млн.' & @CRLF 
$sText &= 'Страна: США; Столица: Вашингтон; Население: 313млн.' & @CRLF 
$sText &= 'Страна: Румыния; Столица: Бухарест; Население: 21млн.' 
$sPattern = 'Страна:\s(?(?=Р).+|[^;]+)' 
$aResult = StringRegExp($sText, $sPattern, 3) 
_ArrayDisplay($aResult)

Значение переменной "$sText" заменить на:
Код:
$sText = 'Страна: Китай; Столица: Пекин; Население: 1347млн.' & @LF & _
		'Страна: Россия; Столица: Москва; Население: 144млн.' & @LF & _
		'Страна: США; Столица: Вашингтон; Население: 313млн.' & @LF & _
		'Страна: Румыния; Столица: Бухарест; Население: 21млн.'


И еще:
  • Урок 3. -> Условные подмаски... -> (Спойлер) Условные подмаски
    важное замечание сказал(а):
    Есть один неприятный момент - при использовании условных масок (даже при использовании групп без захвата) в вывод попадает все что лежит за условной подмаской и записано в шаблоне, во всяком случае у меня не получилось иначе.
    ...
    Если кто-то найдет решение - прошу написать об этом, но ИМХО тут дело не в условных масках, а в самом механизме RegExp.

    Код 1:
    Код:
    ; Пример (шаблон типа "(?(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]')

    Из своих наблюдений:
    - Условные подмаски не являются группами назначенными для захвата, т.е. их нужно рассматривать как "(?:...)".
 
Верх