Регулярные выражения – Жадность

regexp-6 Просто отличное название для очередной статьи о регулярных выражениях в блоге посвященном PowerShell 🙂 Но оно действительно подходит лучше всего. Сегодня мы поговорим об одной важной концепции регулярных выражений. От чего зависит сколько символов будет захвачено количественным модификатором с варьирующейся длинной? Именно от жадности 🙂 Если вы наткнулись на пост случайно, то сначала лучше ознакомьтесь с предыдущими постами серии — 1,2,3,4,5.

По умолчанию, все количественные модификаторы в регулярных выражениях — жадные. То есть они пытаются захватить как можно больше символов (разумеется пока это позволяют условия). Взять к примеру .+ Это выражение означает 1 или более вхождений, но разве оно остановится на одном вхождении? Нет! Оно будет жрать захватывать символы пока у него будет эта возможность, то есть до ограничителя если он есть, а если его нет — то до конца (или начала) строки. Например:

PS C:\> "Очень вкусная булка." -replace "б\S+"
Очень вкусная

Заметьте, захавал всё, и даже точкой не подавился 🙂 А что если мы допускаем любое количество повторений группы, но хотим ограничиться минимумом? Тогда нам поможет "нежадная" версия этого количественного модификатора:

PS C:\> "Очень вкусная булка." -replace "б\S+?"
Очень вкусная лка.

Да, просто добавив после этого количественного модификатора вопросительный знак, мы сразу заставили его ограничится минимумом — одним символом. Нежадные версии других количественных модификаторов получаются таким же образом: *? ?? {1,5}?

Разумеется нежадный модификатор может захватить и больше, но только если у него не останется другого выбора:

PS C:\> "Очень вкусная булка." -replace "б\S+?\."
Очень вкусная

В этом выражении оговаривается что \S+? должен захватить минимум, но до следующей точки.

Маскировка служебных символов в регулярных выражениях, в отличии от других строк PowerShell, делается с помощью символа \ Например

\. Точка
\( Открывающая скобка
\\ Обратный слеш

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

И еще один пример полезности нежадных квантификаторов:

PS C:\> "Теги <123> надо удалить <456>." -replace '<.+>'
Теги .
PS C:\> "Теги <123> надо удалить <456>." -replace '<.+?>'
Теги  надо удалить .

Впрочем… конкретно в этой ситуации можно поступить и иначе:

PS C:\> "Теги <123> надо удалить <456>." -replace '<[^>]+>'
Теги  надо удалить .

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

Разумеется подобные "нежадные" модификаторы можно использовать не только в -replace:

PS C:\> "Число 123." -match '\d+'
True
PS C:\> $matches

Name                           Value
----                           -----
0                              123


PS C:\> "Число 123." -match '\d+?'
True
PS C:\> $matches

Name                           Value
----                           -----
0                              1

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

PS C:\Windows\system32> if ('123456' -match '^(\d+)(\d+)$') {$matches}

Name                           Value
----                           -----
2                              6
1                              12345
0                              123456

Тут первый \d+ захватил максимум цифр, оставив второму лишь минимально необходимое для него – одну. Если же использовать нежадные версии, то первый квантификатор постарается захватить минимум, а уж всё остальное придётся захватывать второму:

PS C:\Windows\system32> if ('123456' -match '^(\d+?)(\d+?)$') {$matches}

Name                           Value
----                           -----
2                              23456
1                              1
0                              123456

 

Продолжение: Select-String

Опубликовано в Regular Expressions. Метки: . 3 комментария »

комментария 3 to “Регулярные выражения – Жадность”

  1. Регулярные выражения – Select-String « PowerShell и другие скрипты Says:

    […] операторами –replace и –split, а так же с концепцией “жадности”. Пришло время познакомится с целым командлетом […]

  2. Регулярные выражения – Switch « PowerShell и другие скрипты Says:

    […] которые рекомендуется прочитать сначала: 1, 2, 3, 4, 5, 6, […]

  3. Скрипт поиска файлов-писем (почтовых сообщений) по полю “Subject” (“Тема”) « ShS's Blog Says:

    […] – нежадная группа захвата, которая захватит и сохранит для нас […]


Обсуждение закрыто.