Расширьте свои знания о регулярных выражениях

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

Основы

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

В любом случае, что такое регулярное выражение?

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

«Последовательность символов» - это синтаксис регулярных выражений, и если вы когда-нибудь видели ее, то знаете, насколько она чужда для чтения, не говоря уже о понимании, особенно на первых порах. Например:

^\(?[0-9]{3}\)?[\-\s]?[0-9]{3}[\-\s]?[0-9]{4}$

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

Когда использовать регулярные выражения, а когда нет

Регулярные выражения полезны программно:

  • Найдите шаблоны и совпадения в наборах данных: будь то .csv или .txt, они помогут вам
  • Проверка форм и входных данных: сделайте это на веб-интерфейсе перед отправкой формы, чтобы убедиться, что после отправки не возникнет никаких проблем.
  • Очистка информации из Интернета: хотите очистить каждую ссылку (<a></a>) с веб-страницы? Для этого есть выражение.

Каковы ограничения регулярных выражений?

  • Регулярные выражения - это не язык программирования. Это инструменты, и все основные языки используют их.
  • Сложно читать. Это довольно пугает, особенно если вы не знакомы с ними, и большинство людей, в том числе и я, стараются держаться от них подальше как можно дольше.
  • Может быть сложно правильно писать, даже если вы знаете, что делаете. Иногда требуется больше, чем несколько попыток, чтобы заставить его работать именно так, как вы хотите.

Различные типы регулярных выражений

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

Базовый и расширенный набор

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

Символы базового набора

. - точка (подстановочный знак): заменяет любой символ

^ — каретка: соответствует началу строки

$ - знак доллара: соответствует концу строки

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

\ - косая черта: представляет специальные символы и экранирует символы.

() - скобка: группирует выражения вместе

? - вопросительный знак: соответствует нулю или одному предыдущего выражения.

\s - экранированный символ "s": представляет собой пробел

[wxyz] - квадратные скобки, литерал: представляет один из символов внутри (w, x, y или z)

[w-z]— квадратная скобка, диапазон: представляет один символ внутри диапазона (w, x, y или z), также может использоваться с числами [10–100].

[^wxyz] - квадратные скобки, отрицание: представляет любой символ, не в наборе (любой, кроме w, x, y или z). Обратите внимание, что символ вставки внутри квадратных скобок имеет другое значение, чем вставка сверху.

\w - слово: соответствует любой букве ASCII, цифре или знаку подчеркивания

Символы расширенного набора

+ - знак плюса: соответствует предыдущему выражению один или несколько раз.

| - вертикальная черта: используется как оператор сравнения или. Будет соответствовать либо выражение1 ИЛИ выражение2: выражение1 | выражение2

{n}— будет соответствовать «n» вхождений предыдущего выражения, аналогично *, + и ?, за исключением случаев, когда вы определяете максимальное количество вхождений с помощью n.

Основное различие, о котором следует помнить при использовании базового набора и расширенного набора, будет заключаться в терминале. Например, за grep при использовании символов из расширенного набора должен следовать -E.

grep -E ‘your-extended-regex’

Разрушение выражения

Давайте вернемся к этому выражению с самого начала:

^\(?[0-9]{3}\)?[\-\s]?[0-9]{3}[\-\s]?[0-9]{4}$

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

^ - каретка: это означает начало нашей строки. Очень просто.

\(? - необязательная открывающая скобка: сначала мы экранируем \, чтобы он читался как буквальный символ (. Затем мы добавим ?, чтобы искать его либо ноль, либо один раз, что делает его необязательным.

[0–9]{3} - ищет любые три последовательных номера, также называемых кодом города (305, 801, 702).

\)? - необязательная закрывающая скобка

На этом этапе выражение будет соответствовать либо 123, либо (123).

[\-\s]? - необязательный пробел или тире: \s - это выражение для пробела или пробела, заключенное в скобки с \- (экранированное тире), за которым следует ?, поэтому он будет искать его ноль или один раз.

[0-9]{3} - ищет любые три последовательных числа

[\-\s]? - необязательный дефис или пробел.

[0-9]{4} — последнее выражение перед конечным тегом, ищет любые четыре последовательных числа.

$ - конец строки.

В этом случае как ^, так и $ можно опустить, и они не требуются для этого конкретного выражения. Я оставил их, потому что их полезно знать и работать в любом случае для этого сценария. Если номер телефона был в середине другого текста, вы бы хотели пропустить их оба.

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

  • 1234567891
  • 123 456 7891
  • 123 456–7891
  • 123–456–7891
  • (123) 456 7891
  • (123) 456–7891

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

[0-9]{10} -, вероятно, самый простой способ проверить, не будет совпадать, если включены дефисы, пробелы или круглые скобки. Ищет только последовательные десятизначные числа.

[0-9]{3}[0-9]{3}[0-9]{4} - другой способ записи последовательного десятизначного числового выражения (по сути, идентично приведенному выше выражению), упрощает добавление дефисов или пробелов.

[0-9]{3}[\-\s]?[0-9]{3}[\-\s]?[0-9]{4} - то же, что и ранее, с проверкой дефисов и пробелов

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

Регулярное выражение для соответствия адресу электронной почты

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

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

  1. Что нужно включить или исключить?
  2. Найдите закономерности во включениях / исключениях.
  3. Запишите эти шаблоны в RegEx.

Рассмотрим эти электронные письма в качестве примера:

Давайте применим к нашему электронному письму описанный выше трехэтапный процесс.

  1. Что нужно включить или исключить?
    - Мы разделим электронные письма на части.
    <username>@<second-level-domain>.<top-level-domain>
    - Домен верхнего уровня может оканчиваться на .com , .net, .org и т. д. В этом примере мы скажем, что максимальная длина будет равна четырем (что-то вроде .info).
  2. Найдите шаблоны во включениях / исключениях
    . Имя пользователя должно быть достаточно открытым, но мы не будем разрешать использование специальных символов, кроме подчеркивания, дефисов и точек.
    - У нас будет фиксированный символ @
    - Домен второго уровня будет исключать специальные символы, за исключением подчеркиваний, дефисов и точек.
    - Домен верхнего уровня должен состоять только из букв и иметь макс. длина четыре и минимальная длина два.
  3. Запишите эти шаблоны в регулярном выражении
    - имя пользователя, [\w\-\.]+, \w соответствует любой букве, цифре и символу подчеркивания ASCII. \- - буквальное прочерк. \. - это точка. Заключите их в квадратные скобки, чтобы они соответствовали любому из них, и добавьте + после, чтобы включить его один или несколько раз.
    - Исправлено совпадение символа @ с символом @ и никаким другим. Это обязательно.
    - Домен второго уровня, ([\w\-]+\.)+, аналогично выражению имени пользователя, за исключением того, что он позволяет объединять несколько выражений вместе и группируется скобками () (example@myurl.co.uk)
    - Домен верхнего уровня, [a-zA-Z]{2,4}, позволяет использовать строчные и прописные буквы от «A» до «Z» от двух до четырех символов.

Сложите все это вместе с кареткой в ​​начале и знаком доллара в конце, и давайте посмотрим, как это выглядит.

^[\w\-\.]+@([\w\-]+\.)+[a-zA-Z]{2,4}$

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

Задача: напишите указанное выше регулярное выражение, не используя \w в любом месте выражения.

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

Примечание.
Различные механизмы обработки регулярных выражений обрабатывают выражения по-своему. Иногда то, что работает на regexr.com или в grep, может не работать в Python и наоборот. Возможно, вам придется поэкспериментировать и попробовать составить регулярные выражения несколькими способами, прежде чем все заработает должным образом

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

В этом примере мы будем использовать grep. Grep - это утилита командной строки, используемая для поиска наборов данных в виде обычного текста, и в нее встроен собственный механизм регулярных выражений! Давайте возьмем номера телефонов и адреса электронной почты, которые мы использовали до этого момента, и добавим их в файл .txt, по которому мы сможем выполнять поиск. Скопируйте текст ниже и вставьте его в окно терминала.

cat << EOF >> regex-test.txt
1234567891
123 456 7891
123 456-7891
123-456-7891
(123) 456 7891
(123) 456-7891
[email protected]
[email protected]
[email protected]
EOF

Это создаст новый файл с именем regex-test.txt, в котором будут храниться номера телефонов и адреса электронной почты. Отсюда мы можем использовать grep для поиска совпадений.

В моей версии grep (2.5.1) \s не всегда работает для определения пробелов. Из-за этого вам может потребоваться или не потребуется заменять экземпляры \s на [:space:] или просто на фактический пробел. Имея это в виду, вот обновленное регулярное выражение, которое будет использоваться с grep для поиска телефонных номеров. Обратите внимание, что я изменил \s на [:space:] и удалил ^ и $.

Регулярное выражение телефонного номера: для использования с grep
\(?[0-9]{3}\)?[-[:space:]]?[0-9]{3}[-[:space:]]?[0-9]{4}

Собрав все вместе, запустите эту команду в том же каталоге, что и только что созданный файл regex-test.txt. Если это не сработает, попробуйте заменить пробел либо \s, либо просто пробелом.

grep -E '\(?[0-9]{3}\)?[-[:space:]]?[0-9]{3}[-[:space:]]?[0-9]{4}' regex-test.txt

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

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

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

В этом примере я добавил электронные письма в список, и мы пройдемся по нему, чтобы проверить каждое по отдельности. Если адрес электронной почты совпадает, он напечатает match.group () - то, с чем он сопоставлен, - а если он не совпадает, напечатает «Недействительный адрес электронной почты».

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

Заключение

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

Полезные ссылки
- Визуализатор регулярных выражений
- Regexr
- Python Regular Expression HOWTO