DC - Синтаксис регулярных выражений

# 2.11. Синтаксис регулярных выражений

## Содержание

1. Введение
2. Простое сравнение
3. Escape-последовательности
4. Наборы символов
5. Метасимволы
  5.1. Метасимволы - разделители строк
  5.2. Метасимволы - стандартные наборы символов
  5.3. Метасимволы - границы слов
  5.4. Метасимволы - повторения
  5.5. Метасимволы - варианты
  5.6. Метасимволы - подвыражения
  5.7. Метасимволы - обратные ссылки
6. Модификаторы

Double Commander использует свободную Delphi-библиотеку TRegExpr Андрея В. Сорокина: https://regex.sorokin.engineer/ru/latest/. Большинство из приведённых далее объяснений и примеров позаимствовано из справочного файла к этой библиотеке.

## 1. Введение

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

Специальные метасимволы позволяют определять, например, что мы ищем подстроку в начале входной строки или n повторений определённого символа.

Регулярные выражения предназначены главным образом для профессионалов, однако могут быть полезны и при работе в офисе для поиска определённых документов (см. примеры ниже).

Double Commander поддерживает регулярные выражения в следующих функциях:

- Команды > Поиск файлов (в имени файла)
- Во встроенном редакторе
- В инструменте группового переименования

(наверх)

## 2. Простое сравнение

Любой символ совпадает с самим собой, если он не относится к специальным метасимволам, описанным чуть ниже.

Последовательность символов совпадает с такой же последовательностью во входной строке, так что шаблон "bluh" совпадет с подстрокой "bluh" во входной строке.

Если необходимо, чтобы метасимволы или escape-последовательности воспринимались как обычные символы, их нужно предварять символом "\" ("экранировать"), например, метасимвол "^" обычно совпадает с началом строк, однако, если записать его как "\^", то он будет совпадать с символом "^", "\\" совпадает с "\" и т.д.

Примеры:

Примеры простого сравнения
Выражение | Результат
--- | ---
foobar | находит "foobar"
\^FooBarPtr | находит "^FooBarPtr"

(наверх)

## 3. Escape-последовательности

Любой символ может быть определён с помощью escape-последовательности так же, как это делается в языках C или Perl: "\n" означает начало строки, "\t" — табуляцию и т.д.

\xnn, где nn — это последовательность шестнадцатеричных цифр, означает символ с ASCII-кодом nn.

Если необходимо определить двухбайтный (Юникод) символ, используем формат "\x{nnnn}", где "nnnn" — одна или более шестнадцатеричных цифр.

Escape-последовательности
Выражение | Результат
--- | ---
\xnn | символ с шестнадцатеричным кодом nn
\x{nnnn} | символ с шестнадцатеричным кодом nnnn (один байт для обычного текста и два для Юникода)
\t | табуляция (HT/TAB), можно также \x09
\n | новая строка (NL/LF), можно также \x0a
\r | возврат каретки (CR), можно также \x0d
\f | перевод страницы (FF), можно также \x0c
\a | звонок (BEL), можно также \x07
\e | escape (ESC), можно также \x1b

Примеры:

Примеры с escape-последовательностями
Выражение | Результат
--- | ---
foo\x20bar | находит "foo bar" (обратите внимание на пробел посередине)
\tfoobar | находит табуляцию и "foobar"

(наверх)

## 4. Наборы символов

Вы можете определить набор, заключив символы в []. Набор будет совпадать с любым одним символов из перечисленных в нём.

Если первым символом набора (сразу после "[") идёт "^", то такой набор совпадает с любым символом не перечисленным в наборе.

Внутри набора символ "-" может быть использован для определения диапазона символов, например, a-z представляет все символы между "a" и "z", включительно.

Если необходимо включить в набор сам символ "-", поместите его в начало или конец набора или предварите символом "\".

Если вам необходимо поместить в набор сам символ "]", поместите его в самое начало или предварите "\".

Наборы символов
Выражение | Результат
--- | ---
[-az] | "a", "z" или "-"
[az-] | "a", "z" или "-"
[a\-z] | "a", "z" или "-"
[a-z] | любая из 26 строчных латинских букв от "a" до "z"
[\n-\x0D] | #10, #11, #12 или #13
[\d-t] | цифра, "-" или "t"
[]-a] | символ из диапазона "]".."a"

Примеры:

Примеры с наборами символов
Выражение | Результат
--- | ---
foob[aeiou]r | находит "foobar", "foober" и т.д., но не "foobbr", "foobcr" и т.д.
foob[^aeiou]r | находит "foobbr", "foobcr" и т.д., но не "foobar", "foober" и т.д.

(наверх)

## 5. Метасимволы

Метасимволы — это специальные символы, являющиеся важнейшим понятием в регулярных выражениях.

Существует несколько типов метасимволов.

(наверх)

## 5.1. Метасимволы - разделители строк

Выражения, помогающие указать разделители строк.

Разделители строк
Выражение | Результат
--- | ---
^ | начало строки
$ | конец строки
\A | начало текста
\Z | конец текста
. | любой символ в строке

Несколько примеров:

Примеры с разделителями строк
Выражение | Результат
--- | ---
^foobar | находит "foobar" только в начале строки
foobar$ | находит "foobar" только в конце строки
^foobar$ | находит "foobar" только если это единственное слово в строке
foob.r | находит "foobar", "foobbr", "foob1r" и т.д.

Метасимвол "^" по умолчанию совпадает только с началом входного текста, а метасимвол "$" — только с концом текста. Внутренние разделители строк, имеющиеся в тексте, не будут совпадать с "^" и "$".

Однако, если вам необходимо работать с текстом как с многострочным, чтобы "^" совпадал после каждого разделителя строки внутри текста, а "$" — перед каждым разделителем, то вы можете включить модификатор m.

Метасимволы \A и \Z аналогичны "^" и "$", но на них не действует модификатор m, т.е. они всегда совпадают только с началом и концом всего входного текста.

Метасимвол "." по умолчанию совпадает с любым символом, однако, если вы выключите модификатор s, то "." не будет совпадать с разделителями строк.

TRegExpr интерпретирует разделители строк так, как это рекомендовано на www.unicode.org в Technical Standard #18:

"^" совпадает с началом входного текста, а также, если включен модификатор m, с точкой, непосредственно следующей после \x0D\x0A, \x0A или \x0D (если вы используете Юникод-версию TRegExpr, то также \x2028, \x2029, \x0B, \x0C или \x85). Обратите внимание, что он не совпадает в промежутке внутри последовательности \x0D\x0A.

"$" совпадает с концом входного текста, а также, если включен модификатор m, с точкой, непосредственно предшествующей \x0D\x0A, \x0A или \x0D (если вы используете Юникод-версию TRegExpr, то также \x2028, \x2029, \x0B, \x0C или \x85). Обратите внимание, что он не совпадает в промежутке внутри последовательности \x0D\x0A.

"." совпадает с любым символом, но если выключен модификатор s, то "." не совпадает с \x0D\x0A, \x0A и \x0D (если вы используете Юникод-версию TRegExpr, то не совпадает также с \x2028, \x2029, \x0B, \x0C и \x85).

Обратите внимание, что "^.*$" (шаблон для пустой строки) не совпадает с пустой строкой вида \x0D\x0A, но совпадает с \x0A\x0D.

(наверх)

## 5.2. Метасимволы - стандартные наборы символов

Выражения, помогающие указать наборы символов.

Наборы символов
Выражение | Результат
--- | ---
\w | буквенно-цифровой символ или "_", т.е. [A-Za-z0-9_]
\W | не \w
\d | цифра
\D | не \d
\s | любой "пробельный" символ (по умолчанию — [ \t\n\r\f])
\S | не \s

Стандартные наборы \w, \d и \s можно использовать и внутри наборов символов.

Примеры:

Примеры со стандартными наборами
Выражение | Результат
--- | ---
foob\dr | находит "foob1r", "foob6r" и т.д., но не "foobar", "foobbr" и т.д.
foob[\w\s]r | находит "foobar", "foob r", "foobbr" и т.д., но не "foob=r" и т.д.

(наверх)

## 5.3. Метасимволы - границы слов

Граница слова (\b) — позиция между двумя символами, один из которых удовлетворяет \w, а другой — \W (в любом порядке), при этом перед началом и после конца строки подразумевается \W.

Границы слов
Выражение | Результат
--- | ---
\b | совпадает на границе слов
\B | совпадает не на границе слов

(наверх)

## 5.4. Метасимволы - повторения

После любого элемента регулярного выражения может следовать очень важный тип метасимвола — повторитель (квантификатор).

Используя их, вы можете определить число допустимых повторений предшествующего символа, метасимвола или подвыражения.

Повторители
Выражение | Результат
--- | ---
* | ноль или более раз ("жадный"), то же, что и {0,}
+ | один или более раз ("жадный"), то же, что и {1,}
? | ноль или один раз ("жадный"), то же, что и {0,1}
{n} | точно n раз ("жадный")
{n,} | не менее n раз ("жадный")
{n,m} | не менее n, но не более m раз ("жадный")
*? | ноль или более раз ("не жадный"), то же, что и {0,}?
+? | один или более раз ("не жадный"), то же, что и {1,}?
?? | ноль или один раз ("не жадный"), то же, что и {0,1}?
{n}? | точно n раз ("не жадный")
{n,}? | не менее n раз ("не жадный")
{n,m}? | не менее n, но не более m раз ("не жадный")

Таким образом, {n,m} задаёт минимум n повторов и максимум — m.

Повторитель {n} эквивалентен {n,n} и задаёт точно n повторов.

Повторитель {n,} задаёт минимум n повторов.

Теоретически величина параметров n и m не ограничена, но рекомендуется не задавать большие значения, поскольку в связи с рекурсивным характером работы обработка такого повторителя в некоторых ситуациях может потребовать существенных затрат времени и ОЗУ.

Если фигурные скобки встречаются в "неправильном" месте, где они не могут быть восприняты как повторитель, то они воспринимаются просто как символы.

Несколько примеров:

Примеры повторителей
Выражение | Результат
--- | ---
foob.*r | находит "foobar", "foobalkjdflkj9r" и "foobr"
foob.+r | находит "foobar", "foobalkjdflkj9r", но не "foobr"
foob.?r | находит "foobar", "foobbr" и "foobr", но не "foobalkj9r"
fooba{2}r | находит "foobaar"
fooba{2,}r | находит "foobaar", "foobaaar", "foobaaaar" и т.д.
fooba{2,3}r | находит "foobaar", или "foobaaar", но не "foobaaaar"

Небольшое пояснение по поводу "жадности".

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

Например, "b+" как и "b*" примененные к входной строке "abbbbc" найдут "bbbb", в то время как "b+?" найдёт только "b", а "b*?" — вообще пустую строку; "b{2,3}?" найдёт "bb", в то время как "b{2,3}" найдёт "bbb".

Вы можете переключить все повторители в выражении в "не жадный" режим, воспользовавшись модификатором g.

(наверх)

## 5.5. Метасимволы - варианты

Вы можете определить набор вариантов, используя метасимвол "|" для их разделения, например "fee|fie|foe" найдёт или "fee", или "fie", или "foe" (так же, как "f(e|i|o)e").

В качестве первого варианта воспринимается всё от предыдущего метасимвола ("(", "[" или от начала выражения) до первого метасимвола "|", в качестве последнего — всё от последнего "|" до конца выражения или до ближайшего метасимвола ")".

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

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

Это означает, что варианты не обязательно обеспечат "жадное" поведение.

Например, если применить выражение "foo|foot" ко входной строке "barefoot", то будет найдено "foo" т.к. это первый вариант, который позволил совпасть всему выражению.

Обратите внимание, что метасимвол "|" внутри наборов символов воспринимается как обычный символ, например, [fee|fie|foe] означает ровно то же самое что и [feio|].

Пример:

Пример вариантов
Выражение | Результат
--- | ---
foo(bar|foo) | находит "foobar" или "foofoo"

(наверх)

## 5.6. Метасимволы - подвыражения

Метасимволы ( ... ) могут также использоваться для определения подвыражений — по завершении поиска выражения вы можете обратиться к любому подвыражению, а также подставлять подвыражения как маску.

Подвыражения нумеруются слева направо, в порядке появления открывающих круглых скобок.

Первое подвыражение имеет номер "1", поддерживается до 90 подвыражений (выражение целиком — "0", к нему можно обращаться как "$0" или "$&").

Примеры:

Подвыражения
Выражение | Результат
--- | ---
(foobar){8,10} | находит строку, содержащую 8, 9 или 10 копий "foobar"
foob([0-9]|a+)r | находит "foob0r", "foob1r" , "foobar", "foobaar", "foobaar" и т.д.

Примечания о шаблонах "Заменить на":

- Если вы хотите использовать в шаблоне символы "$" и "\" как есть, то экранируйте их символом "\".
  Пример: "1\$ \- это $2\\rub\\" вернёт "1$ - это <подвыражение2>\rub\".
- Если вы хотите использовать цифры сразу после "$n", то должны взять n в фигурные скобки "{}".
  Например, "a$12bc" вернёт "a<подвыражение12>bc", но "a${1}2bc" вернёт "a<подвыражение1>2bc".

Пример:

Перевернём дату "21.01.2018" > "2018.01.21":
найти: (\d{2})\.(\d{2})\.(\d{4})
заменить: $3.$2.$1

(наверх)

## 5.7. Метасимволы - обратные ссылки

Метасимволы от \1 до \9 интерпретируются как обратные ссылки. \n совпадает с ранее найденным подвыражением #n.

Несколько примеров:

Примеры обратных ссылок
Выражение | Результат
--- | ---
(.)\1+ | находит "aaaa" и "cc"
(.+)\1+ | также находит "abab" и "123123"
(['"]?)(\d+)\1 | находит "13" (в двойных кавычках), или '4' (в одинарных кавычках) или 77 (без кавычек) и т.д.

(наверх)

## 6. Модификаторы

(?imsxr-imsxr)

Модификаторы служат для изменения режимов работы регулярных выражений.

Любой модификатор может располагаться внутри регулярного выражения с помощью специальной конструкции `(?...)`.

Если эта конструкция расположена внутри подвыражения, то она действует только на это подвыражение.

`i`
  Регистронезависимый режим (используются установленные в вашей системе языковые настройки).
`m`
  Воспринимать входной текст как многострочный, при этом метасимволы "^" и "$" будут совпадать не только в начале и конце текста в целом, но и в начале и в конце всех имеющихся в тексте строк (см. также Разделители строк).
`s`
  Воспринимать входной текст как одну строку. При этом метасимвол "." совпадает с любым символом, если же этот модификатор выключен, то он не совпадает с разделителями строк (см. также Разделители строк). По умолчанию включено.
`g`
  Нестандартный модификатор. Выключая его, вы переключаете все повторители в "не жадный" режим (по умолчанию этот модификатор включен). Т.е. если его отключить, то все "+" работают как "+?", "*" как "*?" и т.д.
`x`
  Позволяет форматировать шаблон, чтобы обеспечить более лёгкую читаемость (см. описание ниже).
`r`
  Нестандартный модификатор. Если включен, то диапазон "а-я" включает в себя также букву "ё", "А-Я" включает "Ё", а "а-Я" включает вообще все русские буквы. По умолчанию включен.
`#`
  `(?#text)`: Комментарий, `text` просто игнорируется. Обратите внимание, что в комментарии такого вида невозможно использовать символ ")", поскольку он воспринимается как конец комментария.

Несколько примеров:

Примеры с модификаторами
Выражение | Результат
--- | ---
(?i)Saint-Petersburg | находит "Saint-petersburg" и "Saint-Petersburg"
(?i)Saint-(?-i)Petersburg | находит "Saint-Petersburg", но не "Saint-petersburg"
(?i)(Saint-)?Petersburg | находит "Saint-petersburg" и "saint-petersburg"
((?i)Saint-)?Petersburg | находит "saint-Petersburg", но не "saint-petersburg"

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

Кроме того, если встречается символ #, то все последующие символы до конца строки воспринимаются как комментарий, например:

    (
      (abc) # комментарий 1
        |   # Вы можете использовать пробелы для форматирования выражения - TRegExpr игнорирует их
      (efg) # комментарий 2
    )

Естественно, это означает, что если вам нужно вставить в выражение пробел, табуляцию, разделитель строки или #, то в расширенном (x) режиме это можно сделать предваряя их "\" или используя escape-последовательность \xnn (внутри наборов символов все эти символы воспринимаются как обычно).

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

(наверх)