# Регулярные выражения

    Это приложение содержит краткое, но достаточно ёмкое описание регулярных выражений в той форме, в которой они используются в &kappname; (они не совместимы с регулярными выражениями perl и grep).

## Введение

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

Приведём небольшой пример. Допустим, требуется найти в тексте все абзацы, которые начинаются с фамилий Петров или Иванов, за которыми следует любая форма глагола рассказывать (для чистоты эксперимента возьмём всего две формы: рассказал и рассказывал).

С помощью обычного поиска понадобилось бы сначала найти фамилию Петров, возможно, дополненную буквами рассказ, что-то вроде этого: `Петров рассказ`. При поиске совпадений пришлось бы пропускать все строки, которые стоят не в начале абзаца. После этого последовал бы повторный поиск для второй фамилии...

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

Регулярные выражения содержат правила, позволяющие точно выразить вид строки для поиска. Приведённый пример возможно выразить словесно: Строка, начинающаяся со слов Петров или Иванов, перед которыми могут стоять до четырёх пробелов или символов табуляции, после фамилии должен стоять пробел, за пробелом — рассказ, после чего может (необязательно!) стоять суффикс ыв, и, наконец, суффикс ал. Это возможно записать в форме регулярного выражения:

`^[ \t]{0,4}(Петров|Иванов) рассказ(ыв)?ал`

Этот пример демонстрирует четыре основных понятия современных регулярных выражений:

- Шаблоны

- Утверждения

- Кванторы

- Обратные ссылки

Знак `^`, с которого начинается выражение, — это утверждение, которое подтверждает совпадение только в том случае, если совпавшая цепочка символов начинается с новой строки.

`[ \t]` и `(Петров|Иванов) рассказ(ыв)?ал` — это шаблоны. Первый представляет собой символьный класс, который совпадает либо с пробелом, либо с символом табуляции. Второй содержит вложенный шаблон, совпадающий со словами `Петров` или `Иванов`, затем идёт проверка на точное совпадение со строкой `рассказ`, потом ещё один вложенный шаблон, который определяет вхождение символов `ыв`, и, в самом конце, проверка на точное совпадение с символами `ал`

Строка `{0,4}` и символ вопроса после вложенного шаблона `(ыв)` — это кванторы. Первый интерпретируется следующим образом: возможен повтор предыдущего символа от 0 до 4 раз. Второй квантор действует аналогично, позволяя повторить стоящий перед ним вложенный шаблон 0 или 1 раз.

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

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

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

## Шаблоны

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

### Управляющие последовательности

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

Делается это очень просто, необходимо всего лишь поставить перед таким символом обратную черту (`\`).

Анализатор регулярных выражений игнорирует обратную черту перед символами, которые не имеют специального значения в контексте; например, если вместо обычного символа j ввести `\j`, анализатор будет интерпретировать его просто как j. Таким образом, если неизвестно, имеет ли символ специальное значение, возможно без опасений предварить его обратной чертой.

Для указания собственно обратной черты (в качестве обычного символа) необходимо продублировать её: `\\`.

### Символьные классы и сокращения

Символьный класс — это выражение, которое позволяет проверить один символ на принадлежность определённому набору символов. Чтобы использовать его в регулярных выражениях, требуется в квадратных скобках записать все верные символы или сокращённые классы, описание которых приводится далее.

Простые символьные классы содержат один или несколько символов, например, `[abc]` (проверка на любой из символов a, b или c) или `[0123456789]` (проверка на любую цифру).

Поскольку буквы и цифры упорядочены логически, возможно сокращать классы, используя диапазоны: `[a-c]` аналогично `[abc]`, `[0-9]` аналогично `[0123456789]`. Возможно комбинировать диапазоны с обычным перечислением символов: `[a-fynot1-38]` (проверка на любой из символов a,b,c,d, e,f,y,n,o,t, 1,2,3 или 8).

Чтобы проверить символ без учёта регистра в любом случае (регулярное выражение позволяет учитывать или не учитывать регистр символов), следует написать примерно следующее: `[aAbB]`.

Возможно создать исключающий класс, который проверяет символ на невхождение в заданный набор символов. Обычный символьный класс превращается в исключающий добавлением символа `^` перед набором символов:

`[^abc]` — проверка на любой символ, кроме a, b и c.

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

`\a`

- Проверка на &ASCII;-символ звонка (BEL, 0x07).

`\f`

- Проверка на &ASCII;-символ перевода страницы (FF, 0x0C).

`\n`

- Проверка на &ASCII;-символ перевода строки (LF, 0x0A, символ перехода на новую строку в Unix).

`\r`

- Проверка на &ASCII;-символ возврата каретки (CR, 0x0D).

`\t`

- Проверка на &ASCII;-символ горизонтальной табуляции (HT, 0x09).

`\v`

- Проверка на &ASCII;-символ вертикальной табуляции (VT, 0x0B).

`\xhhhh`

- Проверка на символ Юникода, соответствующий шестнадцатеричному числу hhhh (в пределах 0x0000-0xFFFF). \0ooo (первый символ — ноль) — проверка на символ в кодировке &ASCII;/Latin-1, соответствующий восьмеричному числу ooo (в пределах 0-0377).

`.` (точка)

- Проверка на любой символ (включая переход на новую строку).

`\d`

- Проверка на цифровой символ. Аналогично классу `[0-9]`.

`\D`

- Проверка на любой символ, не являющийся цифровым. Аналогично `[^0-9]` или `[^\d]`.

`\s`

- Проверка на пробельный символ. Фактически аналогично классу `[ \t\n\r]`.

`\S`

- Проверка на любой символ, не являющийся пробельным. Фактически равнозначно `[^ \t\r\n]` и аналогично `[^\s]`.

`\w`

- Проверка на любой словообразующий символ (все буквы и цифры, а также символ подчёркивания). Аналогично классу `[a-zA-Z0-9_]`.

`\W`

- Проверка на любой символ, не являющийся словообразующим (все символы, кроме букв, цифр и подчёркиваний). Аналогично классу `[^a-zA-Z0-9_]` или `[^\w]`.

Нотация классов POSIX, `[:<имя класса>:]`, также поддерживается. Например, `[:digit:]` аналогично `\d`, а `[:space:]` — `\s`. Полный перечень символьных классов POSIX доступен здесь.

Аббревиатурные классы возможно помещать в обычные классы; например, чтобы выполнить проверку на словообразующий символ, точку или пробел, возможно ввести следующее: `[\w \.]`

#### Символы со специальным значением в символьных классах

Далее перечислены символы, имеющие специальное значение в определениях символьных классов ([]). Для использования в качестве обычных символов они должны быть предварены обратной чертой.

`]`

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

`^`

- Если находится в начале, объявляет исключающий класс. Чтобы использовать этот символ как обычный символ в начале класса, следует предварить его обратной чертой.

`-` (дефис)

- Объявляет логический диапазон. При использовании внутри символьного класса этот символ всегда следует предварять обратной чертой.

`\` (обратная черта)

- Спецсимвол (escape character). Чтобы использовать его как обычный символ, продублируйте.

### Альтернативы: проверка на один из нескольких шаблонов

Если требуется выполнить проверку на один (любой) шаблон из определённого набора, используйте альтернативы. Чтобы объявить альтернативу, следует все шаблоны набора записать через вертикальную черту (`|`).

Например, чтобы найти любое из имён Вася и Петя, необходимо использовать такое выражение: `Вася|Петя`.

### Вложенные шаблоны

Вложенными называются шаблоны, заключённые в круглые скобки. Они используются в разных целях:

#### Определение альтернатив

С помощью вложенных шаблонов возможно группировать набор альтернатив внутри сложных шаблонов. Альтернативы разделяются символом вертикальной черты (|).

Например, чтобы найти одно из слов int, float или double, возможно использовать шаблон `int|float|double`. Если же требуется найти одно из этих слов, за которым следуют пробелы, а за ними — какие-то символы, то необходимо оформить альтернативу как вложенный шаблон: `(int|float|double)\s+\w+`.

#### Захват совпавшего текста (обратные ссылки)

Вложенный шаблон `(ШАБЛОН)` позволяет использовать обратную ссылку благодаря запоминанию нужной части шаблона. Чтобы не выполнялось запоминание вложенного шаблона, необходимо использовать группу без захвата `(?:ШАБЛОН)`.

Например, если требуется найти два одинаковых слова, разделённых запятой и, возможно, пробелами, возможно использовать такое выражение: `(\w+),\s*\1`. Вложенный шаблон `\w+` выполняет поиск цепочки словообразующих символов, а всё выражение выполняет поиск той же цепочки, за которой следует запятая, далее могут идти пробелы, а за ними — точно такая же цепочка (строка `\1` ссылается на первый вложенный шаблон, заключённый в круглые скобки).

Чтобы избежать неясности при использовании символов `\1`, за которыми следуют цифры (например, `\12` может являться двенадцатым вложенным шаблоном или просто первым вложенным шаблоном с цифрой `2`), вложенные шаблоны, состоящие из нескольких цифр, указываются в формате `\{12}`.

Примеры:

- `\{12}1` = использовать вложенный шаблон 12

- `\123` = запомнить 1, а 23 — обычный текст

#### Утверждения просмотра вперёд

Утверждение просмотра вперёд — это вложенный шаблон, который начинается с символов `?=` или `?!`.

Например, чтобы найти слово Билл, за которым может следовать что угодно, кроме слова Гейтс, следует составить такое выражение: `Билл(?! Гейтс)` (оно совпадёт с Билл Клинтон, Билли хороший мальчик, но не с именем известного магната).

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

Смотрите также раздел Утверждения.

#### Утверждения просмотра назад

Утверждение просмотра назад — это вложенный шаблон, который начинается с символов `?<=` или `?<!`.

Утверждение просмотра назад работает так же, как и утверждение просмотра вперёд, отличие лишь в направлении просмотра. Например, чтобы найти слово град, которому не предшествуют символы вино, следует использовать следующее выражение: `(?<!вино)град`.

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

Смотрите также раздел Утверждения.

### Символы со специальным значением в шаблонах

Следующие символы имеют специальное значение в шаблонах, поэтому, чтобы использовать их в качестве обычных символов, необходимо впереди ставить обратную черту:

`\` (обратная черта)

- С этого символа должны начинаться все спецсимволы.

`^`

- Проверка на начало строки.

`$`

- Проверка на конец строки.

`()` (левая и правая круглые скобки)

- Объявление вложенного шаблона.

`{}` (левая и правая фигурные скобки)

- Объявление численного квантора.

`[]` (левая и правая квадратные скобки)

- Объявление символьного класса.

`|` (вертикальная черта)

- Логическое ИЛИ. Используется для разделения альтернатив.

`+` (плюс)

- Квантор один или более.

`*` (звёздочка)

- Квантор ноль или более.

`?` (знак вопроса)

- Необязательный символ. Можно считать его квантором ноль или один.

## Кванторы

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

Кванторы записываются в фигурных скобках (`{` и `}`). Общий вид квантора: `{[минимальное-количество-совпадений][,[максимальное-количество-совпадений]]}`

Использование кванторов лучше пояснить на примерах:

`{1}`

- Ровно одно появление

`{0,1}`

- Ноль или одно появление

`{,1}`

- То же самое, только короче.

`{5,10}`

- Как минимум 5 повторений, максимум — 10.

`{5,}`

- Как минимум 5 повторений (без верхней границы).

Также определены несколько сокращений:

`*` (звёздочка)

- аналогично `{0,}`, найти любое количество повторений (вплоть до нуля повторений).

`+` (плюс)

- аналогично `{1,}`, как минимум одно появление.

`?` (знак вопроса)

- аналогично `{0,1}`, ноль или одно появление.

### Жадность

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

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

### Примеры использования

Несколько примеров использования кванторов.

`^\d{4,5}\s`

- Совпадёт с 1234 вперед и 12345 стоп, но не совпадёт ни с 567 восемь, ни с 223459 много.

`\s+`

- Проверка на один или более пробельных символов.

`(ля){1,}`

- Совпадёт с ляляля и с подстрокой ля в словах кляча и земля.

`/?>`

- Совпадёт с /> в <closeditem/>, а также с > в строке <openitem>.

## Утверждения

Утверждения накладывают дополнительные условия на проверку регулярного выражения.

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

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

Регулярные выражения, описанные в этом руководстве, поддерживают следующие утверждения:

`^` (начало строки)

- Проверка на начало строки.

  Выражение `^Пётр` совпадёт с Пётр в строке Пётр, здравствуйте!, но не в строке Здравствуйте, Пётр!.

`$` (конец строки)

- Проверка на конец строки поиска.

  Выражение `ты\?$` совпадёт с последним ты в строке — Ты не сделаешь этого! — А ты?, но не совпадёт ни с какой частью строки Ты не сделал этого, так?.

`\b` (граница слова)

- Проверяет, есть ли в данном месте с одной стороны словообразующий символ, а с другой — отличный от словообразующего (необязательно разделитель!).

  Это утверждение используется для поиска границ слов; например, можно использовать два таких утверждения, чтобы найти целое слово. Выражение `\bиз\b` совпадёт с отдельным словом из во фразе Он выпал из этого окна, хорошо хоть, что тут низко, но не совпадёт с из в слове низко.

`\B` (нет границы слова)

- Действие этого утверждения обратно утверждению \b.

  Это значит, что данное утверждение будет совпадать, например, в середине слова: выражение `\Bце\B` совпадёт с це в строке сцена, но не в целое.

`(?=ШАБЛОН)` (подтверждающий просмотр вперёд)

- Утверждения просмотра вперёд действуют аналогично обычным шаблонам, с той лишь разницей, что текст, совпавший (или не совпавший, в зависимости от типа просмотра) с утверждением, не будет включен в результирующее совпадение. Подтверждающий просмотр вперёд проверяет текст на предмет совпадения с ШАБЛОНОМ утверждения.

  Выражение `программ(?=\w)` совпадёт с программ в слове программист, но не во фразе Он написал много хороших программ!.

`(?!ШАБЛОН)` (отрицающий просмотр вперёд)

- Отрицающий просмотр вперёд проверяет текст на предмет несовпадения с ШАБЛОНОМ.

  Выражение `const \w+\b(?!\s*&)` совпадёт с const char в строке const char* foo, но не совпадёт с const QString в const QString& bar, поскольку & совпадает с шаблоном отрицающего просмотра вперёд.

`(?<=ШАБЛОН)` (подтверждающий просмотр назад)

- Утверждения просмотра назад действуют аналогично утверждениям просмотра вперёд, разница заключается только в направлении просмотра. Утверждение просмотра назад проверяет часть строки, которая предшествует возможному совпадению. Подтверждающее утверждение просмотра назад будет совпадать со строкой только в том случае, если ей предшествует ШАБЛОН утверждения, но найденное совпадение не будет включено в результат.

  Выражение `(?<=цвет)ок` совпадёт с ок, если этим символам предшествуют символы цвет (в слове цветок, но не в слове росток или в отдельном слове ок).

`(?<!ШАБЛОН)` (отрицающий просмотр назад)

- Отрицающий просмотр назад проверяет текст на предмет несовпадения с ШАБЛОНОМ.

  Выражение `(?<![\w\.])[0-9]+` совпадёт с 123 в строках =123 и -123, но не совпадёт с 123 в строках .123 и слово123.

`(ШАБЛОН)` (захватываемая группа)

- Вложенный шаблон в круглых скобках будет захвачен и запомнен, что позволяет использовать его в обратных ссылках. Например, выражение `(&quot;+)[^&quot;]*\1` совпадает с `""""текст""""` и `"текст"`.

  Подробные сведения доступны в разделе Захват совпавшего текста (обратные ссылки).

`(?:ШАБЛОН)` (группа без захвата)

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