Я не очень понимаю регулярные выражения. Можете ли вы объяснить их мне в простой для понимания форме? Если есть какие-либо онлайн инструменты или книги, не могли бы вы также дать ссылку на них?
Наиболее важной частью являются концепции. Как только вы поймете, как работают строительные блоки, различия в синтаксисе составляют чуть больше, чем простые диалекты. Слой поверх синтаксиса вашего механизма регулярных выражений - это синтаксис языка программирования, который вы используете. Такие языки, как Perl, снимают большую часть этого усложнения, но вам следует учитывать и другие соображения, если вы используете регулярные выражения в программе на Си.
Если вы думаете о регулярных выражениях как о строительных блоках, которые вы можете смешивать и сопоставлять по своему усмотрению, это поможет вам научиться писать и отлаживать собственные шаблоны, а также понимать шаблоны, написанные другими.
Концептуально, самые простые регулярные выражения - это буквальные символы. ШаблонN
соответствует символу «N».
Регулярные выражения рядом друг с другом соответствуют последовательностям. Например, шаблонNick
соответствует последовательности «N», за которой следует «i», затем «c» и «k».
Если вы когда-либо использовали grep
в Unix - даже если только для поиска обычных строк - вы уже использовали регулярные выражения! (The re
в grep
относится к регулярным выражениям.)
Добавляя небольшую сложность, вы можете сопоставить 'Nick' или 'Nick' с шаблоном [Nn]ick
. Часть в квадратных скобках является классом символов , что означает, что он соответствует точно одному из заключенных символов. Вы также можете использовать диапазоны в классах символов, поэтому [a-c]
соответствует либо «a», либо «b», либо «c».
Шаблон .
является особенным: вместо того, чтобы соответствовать только буквальной точке, он соответствует любому символу † . Концептуально это так же, как действительно большой класс персонажей[-.?+%$A-Za-z0-9...]
.
Думайте о классах персонажей как о меню: выберите только один.
Использование .
может сэкономить много печатать, и есть другие ярлыки для общих шаблонов. Скажем, вы хотите сопоставить цифру: один способ написать это [0-9]
. Цифры часто встречаются, поэтому вместо них можно использовать ярлык \d
. Другие \s
(пробел) и\w
(символы слова: буквенно-цифровые или подчеркивание).
В верхнем регистре варианты их комплементы, поэтому \S
соответствует любому не -whitespace характер, например.
Оттуда вы можете повторить части вашего шаблона с квантификаторами . Например, шаблон ab?c
соответствует 'abc' или 'ac', потому что ?
квантификатор делает подшаблон, который он изменяет, необязательным. Другие квантификаторы
*
(ноль или более раз)+
(один или несколько раз){n}
(ровно n раз){n,}
(не менее n раз){n,m}
(не менее n раз, но не более м раз)Соединяя некоторые из этих блоков, шаблон [Nn]*ick
соответствует всем
Первый матч демонстрирует важный урок: *
всегда удается!Любой шаблон может соответствовать нулю раз.
Несколько других полезных примеров:
[0-9]+
(и его эквивалент \d+
) соответствует любому неотрицательному целому числу\d{4}-\d{2}-\d{2}
соответствует датам в формате 2019-01-01Квантификатор изменяет шаблон непосредственно слева. Вы можете ожидать 0abc+0
совпадения с «0abc0», «0abcabc0» и т. Д., Но шаблон непосредственно слева от квантификатора «плюс» c
. Это означает 0abc+0
совпадение с «0abc0», «0abcc0», «0abccc0» и т. Д.
Чтобы сопоставить одну или несколько последовательностей «abc» с нулями на концах, используйте 0(abc)+0
. Скобки обозначают подшаблон, который может быть количественно определен как единое целое. Механизмам регулярных выражений также свойственно сохранять или «захватывать» часть входного текста, которая соответствует группе в скобках. Такое извлечение битов гораздо более гибко и менее подвержено ошибкам, чем подсчет индексов иsubstr
.
Ранее мы видели один способ сопоставления «Ника» или «Ника». Другой с чередованием, как в Nick|nick
. Помните, что чередование включает в себя все слева и все справа. Использование группирования скобки для ограничения объема |
, например , (Nick|nick)
.
В другом примере вы могли бы эквивалентно написать [a-c]
как a|b|c
, но это, вероятно, будет неоптимальным, потому что многие реализации предполагают, что альтернативы будут иметь длину больше 1.
Хотя некоторые персонажи соответствуют друг другу, другие имеют особое значение. Шаблон \d+
не соответствует обратной косой черте, за которой следует строчная буква D с последующим знаком плюс: чтобы получить его, мы будем использовать \\d\+
. Обратная косая черта удаляет специальное значение от следующего символа.
Квантификаторы регулярных выражений являются жадными. Это означает, что они соответствуют как можно большему количеству текста, в то же время позволяя успешно сопоставить весь шаблон.
Например, скажем, ввод
«Привет, - сказала она, - как дела?»
Вы можете ожидать ".+"
совпадения только с «Hello», а затем будете удивлены, когда увидите, что оно совпадает с «Hello» на всем протяжении «you?».
Чтобы переключиться с жадного на то, что вы можете считать осторожным, добавьте дополнительный ?
в квантификатор. Теперь вы понимаете, как работает \((.+?)\)
пример из вашего вопроса. Он соответствует последовательности буквальной левой круглой скобки, за которой следуют один или несколько символов и оканчивающейся правой круглой скобкой.
Если вы вводите «(123) (456)», то первый захват будет «123». Нежадные квантификаторы хотят, чтобы остальная часть шаблона начала сопоставление как можно скорее.
(Что касается вашей путаницы, я не знаю ни одного диалекта регулярного выражения, где ((.+?))
бы делали то же самое. Я подозреваю, что что-то потеряно при передаче где-то по пути.)
Используйте специальный шаблон ^
для сопоставления только в начале ввода и $
сопоставления только в конце. Создание «форзацев» с вашими шаблонами, когда вы говорите: «Я знаю, что находится впереди и сзади, но дай мне все между», - это полезная техника.
Скажем, вы хотите сопоставить комментарии формы
-- This is a comment --
ты бы написал ^--\s+(.+)\s+--$
.
Регулярные выражения являются рекурсивными, поэтому теперь, когда вы понимаете эти основные правила, вы можете комбинировать их по своему усмотрению.
†: Вышеупомянутое утверждение, которое .
соответствует любому символу, является упрощением для педагогических целей, которое не является строго верным. Точка соответствует любому символу, кроме новой строки, "\n"
но на практике вы редко ожидаете, что шаблон .+
пересекает границу новой строки. В регулярных выражениях Perl есть /s
переключатель и Java Pattern.DOTALL
, например, для .
соответствия любому символу. Для языков, у которых нет такой функции, вы можете использовать что-то вроде [\s\S]
соответствия «любому пробелу или любому непробелу», другими словами, чему угодно.
a{,m}
это не вещь, по крайней мере, в Javascript, Perl и Python.