Урок 4. Использование метасимволов

29.03.2018

Категория: Регулярные выражения

Метасимволы были введены в уроке 2, «Поиск отдельных символов». В этом уроке вы узнаете о дополнительных метасимволах, используемых для указания соответствия с определенными символами или типами символов.

Символ \: новые встречи со старым знакомым

Перед глубоким погружением в мир метасимволов важно понять назначение символа \.

Метасимволы — символы, которые имеют специальное значение в регулярных выражениях. Точка . является метасимволом, который соответствует любому отдельному символу (как объяснялось в уроке 2, «Поиск отдельных символов»). Точно так же левая скобка ([) — метасимвол, который отмечает начало набора (см. урок 3, «Соответствие набору символов»).

Поскольку метасимволы имеют специальное значение в регулярных выражениях, эти символы не могут использоваться для нахождения соответствующих им литералов. Например, вы не можете использовать [, чтобы найти [; точно так же вы не найдете точку . с помощью точки .. Рассмотрим следующий пример. Регулярное выражение используется, чтобы в программе на JavaScript попытаться найти выражение с массивом, содержащее [ и ]:

Текст

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

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

myArray[0]

Результат

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

В этом примере блок текста — фрагмент кода на JavaScript. Регулярное выражение — то, что вы, вероятно, использовали бы в текстовом редакторе. Подразумевается, что оно должно было бы соответствовать буквальному тексту myArray[0], но это не так. Почему не так? В регулярном выражении метасимволы [ и ] используются для того, чтобы определить набор символов (но не сами символы [ и ]), Поэтому шаблону myArray[0] соответствует текст myArray, за которым следует один из членов набора, а 0 — единственный член. Так что myArray[0] соответствует только myArray0.

Как объяснялось в уроке 2, «Поиск отдельных символов», метасимволы можно защитить наклонной чертой влево. Поэтому \. соответствует ., а \[ соответствует [. Каждый метасимвол можно защитить предшествующей ему наклонной чертой влево; защищенный символ соответствует самому себе, а не специальному значению метасимвола. Чтобы на самом деле найти [ и ], эти символы нужно защитить. Далее снова рассмотрим тот же самый пример, на сей раз с защищенными метасимволами:

Текст

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

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

myArray\[0\]

Результат

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

Поиск работал правильно. \[ соответствует [, a \] соответствует ]; так что myArray\[0\] соответствует myArray[0].

Честно говоря, использовать в этом примере регулярное выражение было не особенно необходимо — проще было обойтись поиском буквального текста. Но вообразите, что нужно было бы найти не только myArray[0], но и myArray[1], myArray[2] и т.д. Тогда был бы смысл использовать именно регулярное выражение. Нужно было бы защитить [ и ] и определить символы, которые могли бы встретиться между квадратными скобками. Если бы нужно было найти элементы массива с индексами от 0 до 9, можно было бы использовать следующее регулярное выражение:

myArray\[[0-9]\]
Любой метасимвол, а не только упомянутые здесь, можно защитить предшествующей ему наклонной чертой влево.
Метасимволы, которые являются частью пары (например, [ или ]), нужно защитить, если они не используются как метасимволы, в противном случае синтаксический анализатор регулярных выражений может сгенерировать сообщение об ошибке.

Наклонная черта влево \ используется для защиты метасимволов. Это означает, что сама по себе наклонная черта влево \ рассматривается как метасимвол; она используется для защиты других символов. Как отмечено в уроке 2, «Поиск отдельных символов», чтобы закодировать наклонную черту \, нужно саму ее защитить, т.е. указать ее как \\.

Рассмотрим следующий простой пример. Текст — путь к файлу, в котором используются наклонные черты влево (так принято в DOS и Windows). Теперь вообразите, что этот путь нужно использовать в системе Linux или Unix, и потому вы должны определить местонахождение всех наклонных черт влево для того, чтобы заменить их на наклонные черты вправо:

Текст

\home\ben\sales\

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

\\

Результат

\home\ben\sales\

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

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

Вообще говоря, метасимволы относятся к двум категориям: те, которые используются для поиска текста (они соответствуют искомому тексту; к этому типу относится, например, точка .), и те, которые используются как часть синтаксиса регулярного выражения (к этому типу относятся, например, [ и ]). Метасимволов обоих типов много, и проще всего начать с метасимволов, соответствующих пробельным символам.

Когда вы с помощью регулярного выражения выполняете поиск, часто необходимо найти совпадение с непечатаемыми пробельными символами, входящими в текст. Например, иногда нужно найти все символы табуляции, или все концы строк. Поскольку непосредственно ввести такой символ в регулярное выражение было бы весьма непросто, имеются специальные метасимволы, перечисленные в таблице 4.1.

Таблица 4.1. Метасимволы, обозначающие пробельные символы

Метасимвол Описание метасимвола
[\b] Возврат на один символ (Backspace)
\f Перевод страницы (Form feed)
\n Перевод строки (Line feed)
\r Перевод каретки (Carriage return, CR)
\t Табуляция (Tab)
\v Вертикальная табуляция (Vertical tab)

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

Текст

"101","Ben","Forta" 
"102","Jim","James"

"103","Roberta","Robertson"
"104","Bob","Bobson"

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

\r\n\r\n

Результат

"101","Ben","Forta" 
"102","Jim","James" 
 
"103","Roberta","Robertson"
"104","Bob","Bobson"

Выражение \r\n соответствует комбинации перевода строки с переводом каретки, используемой (в Windows) как маркер конца строки. Поэтому \r\n\r\n соответствует двум маркерам конца строки, т.е. пустой строке между двумя записями.

В Windows в качестве маркера конца строки используется \r\n, однако в системе Unix (и Linux) применяется только символ перевода строки. В этих системах нужно будет использовать только \n (без \r). Идеальное регулярное выражение, вероятно, должно учитывать оба случая и потому должно содержать необязательный символ \r и требуемый \n. Поэтому в следующем уроке этот пример придется рассмотреть повторно.

Чаще всего используются метасимволы \r и \n, а также \t (табуляция). Другие пробельные символы обычно применяются редко.

Вы только что познакомились с двумя разновидностями метасимволов. Точка . и открывающая квадратная скобка [ — метасимволы, если они не защищены. Символы f и n, например, являются метасимволами только тогда, когда они защищены. Если они не защищены, то они — буквальные символы, которые соответствуют только самим себе.

Поиск символов определенных типов

К настоящему времени вы знаете, как найти конкретный символ или любой символ (используя точку .), один символ из набора (используя для определения набора [ и ]), и как отрицать соответствие (используя ^). Наборы символов (соответствие одному символу из набора) — самая употребительная форма соответствия, и вместо обычно используемых наборов могут использоваться специальные метасимволы. Говорят, что эти метасимволы соответствуют классам символов. Теоретически метасимволы для обозначения классов не являются необходимыми (ведь всегда можно перечислить символы нужного класса или использовать диапазоны), но на практике они невероятно полезны.

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

Поиск цифр (и нецифровых символов)

Как вы уже знаете из урока 3, «Соответствие набору символов», [0-9] — сокращение для [0123456789]; оно используется для поиска любой цифры. Чтобы найти что-нибудь отличное от цифры, этот набор может быть инвертирован: [^0-9]. В табл. 4.2 перечислены сокращения для класса цифр и класса нецифровых символов.

Таблица 4.2. Метасимволы цифр

Метасимвол Описание метасимвола
\d Любая цифра (digit) (то же самое, что и [0-9])
\D Любой нецифровой символ (то же самое, что и [^0-9])

Чтобы продемонстрировать использование этих метасим волов, давайте повторно рассмотрим предыдущий пример:

Текст

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

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

myArray\[\d\]

Результат

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

Выражение \[ соответствует [, \d соответствует любой от дельной цифре, а \] соответствует ], так что myArray\[\d\] соответствует myArray[0]. myArray\[\d\] — сокращение для myArray\[\[0-9]\], которое в свою очередь является сокращением для myArray\[\[0123456789]\]. Это регулярное выражение также найдет myArray[1], myArray[2], и т.д. (но не найдет myArray[10]).

Почти всегда есть несколько способов определения любого регулярного выражения. Выбирайте тот синтаксис, который вам наиболее удобен.
Синтаксис регулярных выражений чувствителен к регистру. Метасимвол \d соответствует цифрам, a \D — полная противоположность \d. To же самое истинно для метасимволов других классов.
Это справедливо даже при выполнении поиска без учета регистра: когда текст ищется без учета регистра, все равно учитывается регистр специальных символов (например \d).

Поиск алфавитно-цифровых символов (и символов, не относящихся к алфавитно-цифровым)

Есть еще один часто используемый набор — все алфавитно-цифровые символы, т.е. символы от А до z (А на верхнем регистре и z на нижнем регистре), цифры, символ подчеркивания (часто используемый в именах файлов и папок, именах переменных в приложениях, именах объектов баз данных и в других случаях). В табл. 4.3 перечислены сокращения для класса алфавитно-цифровых символов и символов, не относящихся к алфавитно-цифровым.

Следующий пример — выборка из базы данных, содержащей записи с американскими почтовыми индексами и канадскими почтовыми кодами:

Текст

11213 
А1С2ЕЗ 
48075 
48237
M1B4F2
90046
Н1Н2Н2

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

\w\d\w\d\w\d

Результат

11213 
А1С2Е3 
48075 
48237
M1B4F2
90046
Н1Н2Н2

Чтобы отыскать только канадские почтовые коды, шаблон содержит комбинацию метасимволов \w и \d.

Таблица 4.3. Метасимволы для алфавитно-цифровых символов

Метасимвол Описание метасимвола
\w Любой алфавитно-цифровой символ на верхнем или нижнем регистре и символ подчеркивания (то же самое, что и [a-zA-Z0-9_])
\W Любой символ, отличный от символа подчеркивания и не относящийся к алфавитно-цифровым (то же самое, что и [^a-zA-Z0-9_])

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

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

Поиск пробельных символов и символов, не относящихся к ним

Наконец, рассмотрим класс пробельных символов. Вы уже знаете метасимволы для определенных пробельных символов. В табл. 4.4 перечислены сокращения для класса всех пробельных символов.

Таблица 4.4. Метасимволы для класса всех пробельных символов

Метасимвол Описание метасимвола
\s Любой пробельный символ (то же самое, что и [\f\n\r\t\v])
\S Любой непробельный символ (то же самое, что и [^\f\n\r\t\v])
Обратите внимание, что метасимвол возврата на один символ, [\b], не включен в \s и не исключается применением \S.

Указание шестнадцатеричных и восьмеричных значений

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

Указание шестнадцатеричных значений

Чтобы указать шестнадцатеричное (т.е. по основанию 16) значение, перед ним нужно написать . Поэтому \х0А (символ с ASCII-кодом 10, символ перевода строки) функционально эквивалентен \n.

Указание восьмеричных значений

Чтобы указать восьмеричное (т.е. по основанию 8) двух- или трехзначное значение, перед ним нужно написать \0. Поэтому \011 (символ с ASCII-кодом 9, символ табуляции) функционально эквивалентен \t.

Во многих реализациях регулярных выражений допускается также спецификация управляющих символов с помощью \c. Например, \cZ соответствует Ctrl-Z. На практике этот синтаксис используется очень редко.

Использование символьных классов POSIX

Урок по метасимволам и сокращениям для различных наборов символов не был бы полным без упоминания о символьных классах POSIX (табл. 4.5). Они — еще одна форма сокращения, которое поддерживается многими (но не всеми) реализациями регулярных выражений.

JavaScript не поддерживает символьные классы POSIX в регулярных выражениях.

Таблица 4.5. Символьные классы POSIX

Класс Описание класса
[:alnum:] Любой символ или цифра (то же самое, что и [a-zA-Z0-9])
[:alpha:] Любой символ (то же самое, что и [a-zA-Z])
[:blank:] Пробел или табуляция (то же самое, что и [\t ])
[:cntrl:] Управляющие символы ASCII (ASCII-коды от 0 до 31 и 127)
[:digit:] Любая цифра (то же самое, что и [0-9])
[:graph:] То же самое, что и [:print:], но пробел исключен
[:lower:] Любой символ нижнего регистра (то же самое, что и [a-z])
[:print:] Любой печатаемый символ
[:punct:] Любой символ, который не входит ни в [:alnum:], ни в [:cntrl:]
[:space:] Любой пробельный символ, включая пробел (то же самое, что и [\f\n\r\t\v ])
[:upper:] Любая прописная буква (то же самое, что и [А-Z])
[:xdigit:] Любая шестнадцатеричная цифра (то же самое, что и [a-fA-F0-9])

Синтаксис POSIX весьма отличается от синтаксиса ранее изученных метасимволов. Чтобы продемонстрировать использование классов POSIX, повторно рассмотрим пример из предыдущего урока. В примере используем регулярное выражение, чтобы найти RGB-значения в блоке HTML-кода:

Текст

<BODY BGCOLOR="#336633" TEXT="#FFFFFF" 
      MARGINWIDTH="0" MARGINHEIGHT="0"
      TOPMARGIN="0" LEFTMARGIN="0">

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

#[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]

Результат

<BODY BGCOLOR="#336633" TEXT="#FFFFFF" 
      MARGINWIDTH="0" MARGINHEIGHT="0"
      TOPMARGIN="0" LEFTMARGIN="0">

В шаблоне, использованном в предыдущем уроке, набор символов [0-9A-Fa-f] повторялся шесть раз. Здесь каждый набор [0-9A-Fa-f] был заменен на [[:xdigit:]]. Результат тот же самый.

Обратите внимание, что регулярное выражение, используемое в этом примере, начинается с [[ и заканчивается ]] (два набора скобок). Это важно и обязательно при использовании классов POSIX. Классы POSIX заключаются в «скобки» [: и :]; мы использовали выражение POSIX [:xdigit:] (а не :xdigit:). Внешние скобки [ и ] определяют набор; а внутренние скобки [ и ] сами являются частью имени класса POSIX.
Все 12 классов POSIX, перечисленные здесь, поддерживаются в любой реализации, которая поддерживает POSIX. Однако могут быть тонкие отклонения от предыдущих описаний.

Резюме

Опираясь на основные сведения о соответствии символов и наборов, приведенные в уроках 2, «Поиск отдельных символов», и 3, «Соответствие набору символов», в этом уроке мы ввели метасимволы, которые соответствуют определенным символам (таким как табуляция или перевод строки), наборам либо классам символов (таким как цифры или алфавитно-цифровые символы). Эти обозначения метасимволов и классов POSIX могут использоваться для упрощения шаблонов, построенных по правилам языка регулярных выражений.

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.