Сопоставление с шаблоном

QHB предлагает три разных подхода к сопоставлению с шаблоном: традиционный оператор SQL LIKE, более современный оператор SIMILAR TO (добавленный в SQL:1999) и регулярные выражения в стиле POSIX. Помимо основного «эта строка соответствует этому шаблону?», имеются также операторы и функции для извлечения или замены соответствующих подстрок и для разделения строки по совпадающим местам.

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

ВНИМАНИЕ!
Хотя по большей части поиск по регулярным выражениям может выполняться очень быстро, есть вероятность создания регулярных выражений, обработка которых занимает некоторое количество времени и памяти. Остерегайтесь шаблонов поиска по регулярным выражениям, поступающих из неблагоприятных источников. Если вам приходится это делать, рекомендуется установить тайм-аут для операторов.

Поиск с использованием шаблонов SIMILAR TO сопряжен с теми же угрозами безопасности, поскольку SIMILAR TO во многом предоставляет те же возможности, что и регулярные выражения в стиле POSIX.

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

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



LIKE

строка LIKE шаблон [ESCAPE управляющий_символ]
строка NOT LIKE шаблон [ESCAPE управляющий_символ]

Выражение LIKE возвращает true, если строка соответствует предоставленному шаблону. (Как и следовало ожидать, выражение NOT LIKE возвращает false, если LIKE возвращает true, и наоборот. Этому выражению равнозначно выражение NOT (строка LIKE шаблон).)

Если шаблон не содержит знаков процента или подчеркивания, то шаблон представляет только саму строку; в этом случае LIKE действует как оператор равенства. Подчеркивание (_) в шаблоне обозначает (подменяет) любой отдельный символ; знак процента (%) соответствует любой последовательности из нуля и более символов.

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

'abc' LIKE 'abc'    true
'abc' LIKE 'a%'     true
'abc' LIKE '_b_'    true
'abc' LIKE 'c'      false

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

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

Примечание
Если у вас выключен параметр standard_conforming_strings, любые обратные слэши, которые вы пишете в константах литеральных строк, нужно будет дублировать. Дополнительную информацию см. в подразделе Строковые константы.

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

Согласно стандарту SQL, отсутствие указания ESCAPE означает, что управляющий символ не определен (а не становится по умолчанию обратным слэшем), а пустое значение в ESCAPE не допускается. Таким образом, в этом отношении поведение QHB значительно отличается от стандартного.

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

Оператор ~~ равнозначен LIKE, а ~~* соответствует ILIKE. Также имеются операторы !~~ и !~~*, которые представляют NOT LIKE и NOT ILIKE соответственно. Все эти операторы специфичны для QHB. Имена этих операторов можно увидеть в выводе команды EXPLAIN и в иных подобных местах, поскольку синтаксический анализатор фактически заменяет LIKE и прочие на эти операторы.

Фразы LIKE, ILIKE, NOT LIKE и NOT ILIKE в синтаксисе QHB обычно обрабатываются как операторы; например, их можно использовать в конструкциях выражение оператор ANY (подзапрос), хотя предложение ESCAPE сюда включить нельзя. В некоторых сложных случаях может понадобиться использовать вместо них имена нижележащих операторов.

Также есть оператор префикса ^@ и соответствующая функция starts_with, которые полезны в случаях, когда необходимо сопоставление только с началом строки.



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

строка SIMILAR TO шаблон [ESCAPE управляющий_символ]
строка NOT SIMILAR TO шаблон [ESCAPE управляющий_символ]

Оператор SIMILAR TO возвращает true или false в зависимости от того, соответствует ли его шаблон заданной строке. Он похож на LIKE, за исключением того, что он интерпретирует шаблон, используя определение регулярного выражения в стандарте SQL. Регулярные выражения SQL представляют собой любопытную смесь между нотацией LIKE и нотацией обычного (POSIX) регулярного выражения.

Как и LIKE, оператор SIMILAR TO успешно выполняется, только если его шаблон соответствует всей строке; это не похоже на обычное поведение регулярных выражений, когда шаблон может соответствовать любой части строки. Также подобно LIKE, SIMILAR TO использует символы _ и % в качестве подстановочных символов, обозначающих любой отдельный символ и любую строку соответственно (они сопоставимы с . и .* в регулярных выражениях POSIX).

В дополнение к этим возможностям, заимствованным из LIKE, SIMILAR TO поддерживает метасимволы сопоставления с шаблоном, заимствованные из регулярных выражений POSIX:

  • | обозначает чередование (любой из двух вариантов).

  • * обозначает повторение предыдущего пункта ноль и более раз.

  • + обозначает повторение предыдущего пункта один и более раз.

  • ? обозначает повторение предыдущего пункта ноль или один раз.

  • {m} обозначает повторение предыдущего элемента ровно m раз.

  • {m,} обозначает повторение предыдущего элемента m и более раз.

  • {m,n} обозначает повторение предыдущего элемента не менее m и не более n раз.

  • Круглые скобки () могут использоваться для группировки элементов в один логический элемент.

  • Выражение в квадратных скобках [...] определяет класс символов, как и в регулярных выражениях POSIX.

Обратите внимание, что точка (.) не является метасимволом для SIMILAR TO.

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

Согласно стандарту SQL, отсутствие указания ESCAPE означает, что управляющий символ не определен (а не становится по умолчанию обратным слэшем), а пустое значение в ESCAPE не допускается. Таким образом, в этом отношении поведение QHB значительно отличается от стандартного.

Еще одно нестандартное расширение заключается в том, что следующая за управляющим символом буква или цифра открывает доступ к управляющим последовательностям, определенным для регулярных выражений POSIX; см. Таблицу 20, Таблицу 21 и Таблицу 22 ниже.

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

'abc' SIMILAR TO 'abc'      true
'abc' SIMILAR TO 'a'        false
'abc' SIMILAR TO '%(b|d)%'  true
'abc' SIMILAR TO '(b|c)%'   false

Функция substring с тремя параметрами извлекает подстроку, соответствующую шаблону регулярного выражения SQL. Эту функцию можно написать в соответствии со стандартным синтаксисом SQL:

substring(строка similar шаблон escape управляющий_символ)

или используя синтаксис ныне устаревшего SQL:1999:

substring(строка from шаблон for управляющий_символ)

или как простую функцию с тремя аргументами:

substring(строка, шаблон, управляющий_символ)

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

Разделители, состоящие из управляющего символа и кавычек, фактически делят шаблон substring на три независимых регулярных выражения; например, вертикальная черта (|) в любом из трех разделов влияет только на этот раздел. Кроме того, когда есть некоторая неоднозначность относительно того, какая часть строки данных соответствует какому шаблону, первое и третье из этих регулярных выражений определяются так, чтобы соответствовать наименьшему возможному объему текста, а не наибольшему. (Говоря на жаргоне POSIX, первое и третье регулярные выражения должны быть «нежадными»).

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

Несколько примеров с разделителями #", ограничивающими возвращаемую строку:

substring('foobar' from '%#"o_b#"%' for '#')   oob
substring('foobar' from '#"o_b#"%' for '#')    NULL


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

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

Таблица 16. Операторы сопоставления регулярных выражений

Оператор

Описание

Пример(ы)

text ~ text → boolean

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

'thomas' ~ 't.*ma' → t

text ~* text → boolean

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

'thomas' ~* 'T.*ma' → t

text !~ text → boolean

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

'thomas' !~ 't.*max' → t

text !~* text → boolean

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

'thomas' !~* 'T.*ma' → f

Регулярные выражения POSIX предоставляют более мощные средства для сопоставления с шаблоном, чем операторы LIKE и SIMILAR TO. Многие инструменты Unix, такие как egrep, sed или awk, используют язык сопоставления с шаблоном, похожий на описанный здесь.

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

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

'abcd' ~ 'bc'     true
'abcd' ~ 'a.c'    true — точка соответствует любому символу
'abcd' ~ 'a.*d'   true — * повторяет предыдущий элемент шаблона
'abcd' ~ '(b|x)'  true — | означает ИЛИ для группы в скобках
'abcd' ~ '^a'     true — ^ привязывает шаблон к началу строки
'abcd' ~ '^(b|c)' false — совпадение не найдено по причине привязки

Более подробно язык шаблонов POSIX описан ниже.

Функция substring с двумя параметрами substring(строка from шаблон) извлекает подстроку, соответствующую шаблону регулярного выражения POSIX. Возвращает NULL, если совпадения нет, либо первый базовых элемент текста, соответствующий шаблону, в противном случае. Но если шаблон содержит круглые скобки, возвращается часть текста, соответствующая первому подвыражению в скобках (та, чья левая скобка стоит первой). Если вы хотите использовать в выражении круглые скобки, не запуская это исключение, можно заключить в них все выражение. Если вам нужны круглые скобки в шаблоне перед подвыражением, которое вы хотите извлечь, смотрите ниже описание использования скобок без захвата.

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

substring('foobar' from 'o.b')     oob
substring('foobar' from 'o(.)b')   o

Функция regexp_replace подставляет новый текст вместо подстрок, соответствующих шаблонам регулярных выражений POSIX. Она имеет синтаксис regexp_replace(исходная_строка, шаблон, замена [, флаги ]). Если нет совпадения с шаблоном, исходная_строка возвращается без изменений. Если совпадение есть, исходная_строка возвращается с заменой вместо соответствующей подстроки. Строка замена может содержать \n, где n — число от 1 до 9, указывающее, что должна быть вставлена исходная подстрока, соответствующая n-му подвыражению шаблона в скобках, а также может содержать \&, указывающее, что должна быть вставлена подстрока, соответствующая всему шаблону. Если нужно вставить обратный слеш в текст замены буквально, напишите \\. Параметр флаги представляет собой необязательную текстовую строку, содержащую ноль или более однобуквенных флагов, которые изменяют поведение функции. Флаг i указывает, что сопоставление должно проводиться без учета регистра, а флаг g указывает, что заменяться должны все соответствующие подстроки, а не только первая из них. Поддерживаемые флаги (кроме g) описаны в Таблице 24.

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

regexp_replace('foobarbaz', 'b..', 'X')
                                   fooXbaz
regexp_replace('foobarbaz', 'b..', 'X', 'g')
                                   fooXX
regexp_replace('foobarbaz', 'b(..)', 'X\1Y', 'g')
                                   fooXarYXazY

Функция regexp_match возвращает текстовый массив захваченных подстрок, полученных в результате первого сопоставления шаблона регулярного выражения POSIX со строкой. Она имеет синтаксис regexp_match(строка, шаблон [, флаги ]). Если совпадений нет, результатом будет NULL. Если совпадение найдено и шаблон не содержит подвыражений в скобках, то результатом будет текстовый массив из одного элемента, содержащий подстроку, соответствующую всему шаблону. Если совпадение найдено и шаблон содержит подвыражения в скобках, то результатом будет текстовый массив, чей n-й элемент является подстрокой, соответствующей n-му подвыражению в скобках шаблона (не считая «не захватывающих» скобок; подробности см. ниже). Параметр флаги представляет собой необязательную текстовую строку, содержащую ноль или более однобуквенных флагов, изменяющих поведение функции. Поддерживаемые флаги описаны в Таблице 24.

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

SELECT regexp_match('foobarbequebaz', 'bar.*que');
 regexp_match
--------------
 {barbeque}
(1 row)

SELECT regexp_match('foobarbequebaz', '(bar)(beque)');
 regexp_match
--------------
 {bar,beque}
(1 row)

В общем случае, когда вы просто хотите получить всю соответствующую подстроку или NULL, если совпадений нет, напишите что-то вроде

SELECT (regexp_match('foobarbequebaz', 'bar.*que'))[1];
 regexp_match
--------------
 barbeque
(1 row)

Функция regexp_matches возвращает набор текстовых массивов захваченных подстрок, полученных в результате сопоставления шаблона регулярного выражения POSIX со строкой. Она имеет тот же синтаксис, что и regexp_match. Эта функция не возвращает ни одной строки, если совпадения нет, одну строка, если есть совпадение и не задан флаг g, или N строк, если есть N совпадений и задан флаг g. Каждая возвращаемая строка является текстовым массивом, содержащим всю сопоставляемую подстроку или подстроки, соответствующие подвыражениям в скобках шаблона, как описано выше для regexp_match. Функция regexp_matches принимает все флаги, перечисленные в Таблице 24, плюс флаг g, который указывает ей возвращать все совпавшие подстроки, а не только первую.

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

SELECT regexp_matches('foo', 'not there');
 regexp_matches
----------------
(0 rows)

SELECT regexp_matches('foobarbequebazilbarfbonk', '(b[^b]+)(b[^b]+)', 'g');
 regexp_matches
----------------
 {bar,beque}
 {bazil,barf}
(2 rows)

Функция regexp_split_to_table разбивает строку, используя в качестве разделителя шаблон регулярного выражения POSIX. Она имеет синтаксис regexp_split_to_table(строка, шаблон [, флаги ]). Если нет совпадения с шаблоном, функция возвращает строку. Если найдено хотя бы одно совпадение, для каждого его вхождения она возвращает текст от конца предыдущего вхождения (или начала строки) до начала этого вхождения. Дойдя до последнего вхождения, она возвращает текст от конца этого последнего вхождения до конца строки. Параметр флаги представляет собой необязательную текстовую строку, содержащую ноль или более однобуквенных флагов, изменяющих поведение функции. regexp_split_to_table поддерживает флаги, описанные в Таблице 24.

Функция regexp_split_to_array ведет себя так же, как regexp_split_to_table, за исключением того, что regexp_split_to_array возвращает свой результат в виде массива элементов типа text. Она имеет синтаксис regexp_split_to_array(строка, шаблон [, флаги ]). Параметры те же, что и для regexp_split_to_table.

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

SELECT foo FROM regexp_split_to_table('the quick brown fox jumps over the lazy dog', '\s+') AS foo;
  foo   
-------
 the    
 quick  
 brown  
 fox    
 jumps
 over   
 the    
 lazy   
 dog    
(9 rows)

SELECT regexp_split_to_array('the quick brown fox jumps over the lazy dog', '\s+');
              regexp_split_to_array             
-----------------------------------------------
 {the,quick,brown,fox,jumps,over,the,lazy,dog}
(1 row)

SELECT foo FROM regexp_split_to_table('the quick brown fox', '\s*') AS foo;
 foo
-----
 t         
 h         
 e         
 q         
 u         
 i         
 c         
 k         
 b         
 r         
 o         
 w         
 n         
 f         
 o         
 x         
(16 rows)

Как показывает последний пример, функции разбиения по регулярным выражениям игнорируют вхождения нулевой длины, которые находятся в начале или конце строки или сразу после предыдущего вхождения. Это противоречит строгому определению сопоставления по регулярным выражениям, которое реализуется с помощью функций regexp_match и regexp_matches, но обычно на практике является наиболее удобным поведением. Аналогичные определения используют и другие программные системы, например Perl.


Подробное описание регулярных выражений

Регулярные выражения в QHB реализованы с использованием программного пакета, написанного Генри Спенсером (Henry Spencer). Большая часть представленного ниже описания регулярных выражений дословно скопирована из его руководства.

Регулярные выражения (Regular expression, RE), как определено в POSIX 1003.2, имеют две формы: расширенные RE, или ERE (грубо говоря, те, что предназначены для egrep), и базовые RE или BRE (грубо говоря, те, что предназначены для ed). QHB поддерживает обе формы, а также реализует некоторые расширения, которые не входят в стандарт POSIX, но стали широко использоваться благодаря их наличию в таких языках программирования, как Perl и Tcl. RE, использующие эти не предусмотренные в POSIX расширения, в данной документации называются продвинутыми RE, или ARE. ARE являются почти точным надмножеством ERE, но у BRE имеется некоторая несовместимость в нотации (кроме того, они гораздо более ограничены). Сначала мы опишем формы ARE и ERE, отметив черты, характерные только для ARE, а затем опишем, чем отличаются BRE.

Примечание
QHB всегда изначально предполагает, что регулярное выражение следует правилам ARE. Однако можно выбрать более ограниченные правила ERE или BRE, добавив в шаблон RE встроенный параметр, как описано в подразделе Метасинтаксис регулярных выражений. Это может быть полезно для совместимости с приложениями, ожидающими неукоснительного следования правилам POSIX 1003.2.

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

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

Количественный атом — это атом, за которым может следовать один квантификатор. Без квантификатора он соответствует одному вхождению атома. С квантификатором он может соответствовать некоторому количеству вхождений атома. Атом может быть любой из возможностей, показанных в Таблице 17. Возможные квантификаторы и их значения приведены в Таблице 18.

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

Таблица 17. Атомы регулярного выражения

АтомОписание
(re)(где *re - любое регулярное выражение) соответствует вхождению re, причем вхождение отмечено для возможного сообщения
(?: re)то же, что и выше, но вхождение не отмечено для отчетности (набор «не захватывающих» скобок) (только для ARE)
.соответствует любому отдельному символу
[ chars ]выражение в квадратных скобках, соответствующее любому из chars (более подробную информацию см. в подразделе Выражения в квадратных скобках)
\k(где k не буквенно-цифровой символ) соответствует этому символу, взятому как обычный символ, например, \\ соответствует символу обратного слэша
\cгде c — буквенно-цифровой символ (за которым, возможно, следуют другие символы), является управляющим символом, см. подраздел Управляющие символы в регулярных выражениях (только для ARE; в ERE и BRE это соответствует c)
{когда за ним следует символ, отличный от цифры, соответствует символу левой фигурной скобки {; после цифры следует начало границы (см. ниже)
xгде x — это один символ, не имеющий другого значения, соответствует этому символу

RE не может заканчиваться обратным слэшем (\).

Примечание
Если у вас выключен параметр standard_conforming_strings, любые обратные слэши, которые вы пишете в константах литеральных строк, нужно будет дублировать. Дополнительную информацию см. в подразделе Строковые константы.

Таблица 18. Квантификаторы регулярных выражений

КвантификаторСовпадения
*последовательность из 0 или более совпадений атома
+последовательность из 1 или более совпадений атома
?последовательность из 0 или 1 совпадения атома
{m}последовательность из ровно m совпадений атома
{m,}последовательность из m или более совпадений атома
{m,n}последовательность из от m до n (включительно) совпадений атома; m не может превышать n
*?нежадная версия *
+?нежадная версия +
??нежадная версия ?
{m}?нежадная версия {m}
{m,}?нежадная версия {m,}
{m,n}?нежадная версия {m,n}

Формы, использующие {...}, называются границами. Числа m и n внутри границы являются десятичными целыми числами без знака с допустимыми значениями от 0 до 255 включительно.

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

Примечание
Квантификатор не может следовать сразу за другим квантификатором, например, запись ** недействительна. Квантификатор не может начинать выражение или подвыражение или следовать за символом ^ или |.

Таблица 19. Ограничения регулярного выражения

ОграничениеОписание
^соответствует началу строки
$соответствует концу строки
(?=re)позитивный просмотр вперед соответствует любой точке, где начинается подстрока, соответствующая re (только для ARE)
(?!re)негативный просмотр вперед соответствует любой точке, где не начинается подстрока, соответствующая re (только для ARE)
(?<=re)позитивный просмотр назад соответствует любой точке, где заканчивается подстрока, соответствующая re (только для ARE)
(?<!re)негативный просмотр назад соответствует любой точке, где не заканчивается подстрока, соответствующая re (только для ARE)

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


Выражения в квадратных скобках

Выражение в квадратных скобках — это список символов, заключенных в []. Обычно оно соответствует любому отдельному символу из этого списка (но см. ниже). Если список начинается с ^, оно соответствует любому отдельному символу, не относящемуся к остальной части этого списка. Если два символа в списке разделены знаком -, это сокращение для полного диапазона символов между этими двумя символами (включая их) в последовательности сортировки, например, запись [0-9] в ASCII соответствует любой десятичной цифре. Недопустимо, чтобы у двух диапазонов была общая граничная точка, например a-c-e. Диапазоны очень сильно зависят от последовательности сортировки, поэтому переносимые программы не должны полагаться на них.

Чтобы включить в список литерал ], сделайте его первым символом (после ^, если он используется). Чтобы включить литерал -, сделайте его первым или последним символом или второй граничной точкой диапазона. Чтобы использовать литерал - в качестве первой граничной точки диапазона, заключите его в [. и .], чтобы сделать его упорядочивающим элементом (см. ниже). За исключением этих символов, некоторых комбинаций с использованием [ (см. следующие абзацы) и управляющих символов (только для ARE), все другие специальные символы внутри выражения в квадратных скобках теряют свое особое значение. В частности, символ \ является обычным, если следовать правилам ERE или BRE, хотя и является специальным (как обозначающий экранирование) в ARE.

Внутри выражения в квадратных скобках элемент сортировки (символ, многосимвольная последовательность, которая сортируется, как если бы это был один символ, или имя последовательности сортировки для любого из них), заключенный в [. и .], обозначает последовательность символов этого элемента сортировки. Последовательность рассматривается как отдельный элемент списка выражения в квадратных скобках. Это позволяет выражению в квадратных скобках, содержащему многосимвольный элемент сортировки, соответствовать более чем одному символу, например, если последовательность сортировки включает в себя элемент сортировки ch, то RE [[.ch.]]*c соответствует первым пяти символам строки chchcc.

Примечание
В настоящее время QHB не поддерживает многосимвольные элементы сортировки. Эта информация описывает возможное будущее поведение.

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

В выражении в квадратных скобках имя класса символов, заключенное в [: и :], обозначает список всех символов, принадлежащих этому классу. Класс символов не может использоваться в качестве граничной точки диапазона. Стандарт POSIX определяет следующие имена классов символов: alnum (буквы и цифры), alpha (буквы), blank (пробел и табуляция), cntrl (символы управления), digit (цифры), graph (печатные символы, кроме пробела), lower (строчные буквы), print (печатаемые символы, включая пробел), punct (пунктуация), space (любой пробел), upper (заглавные буквы) и xdigit (шестнадцатеричные цифры). Поведение этих стандартных классов символов обычно одинаково на разных платформах для символов в 7-битном наборе ASCII. То, считается ли данный символ, не относящийся к ASCII, принадлежащим одному из этих классов, зависит от правила сортировки, используемого для функции или оператора регулярного выражения (см. раздел Поддержка правил сортировки), или, по умолчанию, от настройки языка LC_CTYPE базы данных (см. раздел Поддержка языковых стандартов). Классификация символов, отличных от ASCII, может варьироваться в зависимости от платформы даже в локалях с одинаковыми именами. (Но локаль C никогда не считает, что любые не относящиеся к ASCII символы принадлежат какому-либо из этих классов). В дополнение к этим стандартным классам символов, QHB определяет класс символов word, который аналогичен alnum, но вдобавок включает символ подчеркивания (_), и класс символов ascii, который содержит только и исключительно 7-битный набор ASCII.

Существует два особых случая выражений в квадратных скобках: выражения [[:<:]] и [[:>:]] являются ограничениями, соответствующими пустым строкам в начале и конце слова соответственно. Слово определяется как последовательность словообразующих символов, которая не предшествует и не сопровождается символами слова. Словообразующий символ — это любой символ, принадлежащий классу символов word, то есть любая буква, цифра или знак подчеркивания. Это расширение совместимо с POSIX 1003.2, но не указано в нем, и его следует использовать с осторожностью в программном обеспечении, предназначенном для переноса на другие системы. Обычно лучше использовать описанные ниже символы ограничений; они тоже не вполне стандартны, но их легче набирать.


Управляющие символы в регулярных выражениях

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

Особые обозначения символов существуют, чтобы упростить указание непечатаемых и других неудобных символов в RE. Они приведены в Таблице 20.

Коды классов предоставляют сокращенные обозначения для некоторых часто используемых классов символов. Они приведены в Таблице 21.

Символы ограничений — это ограничения, которые при выполнении определенных условий соответствуют пустой строке и записываются в виде управляющих символов. Они приведены в Таблице 22.

Обратная ссылка (\n) соответствует той же строке, которой соответствовало предыдущее подвыражение в скобках, указанное числом n (см. Таблицу 22). Например, ([bc])\1 соответствует bb или cc, но не bc или cb. Подвыражение должно полностью предшествовать обратной ссылке в RE. Подвыражения нумеруются в порядке их открывающих скобок. Не захватывающие скобки не определяют подвыражения. Обратные ссылки учитывают только строковые символы, соответствующие указанному подвыражению, но не содержащиеся в нем ограничения. Например, выражению (^\d)\1 будет соответствовать 22.

Таблица 20. Особые обозначения символов в регулярных выражениях

Управляющий символОписание
\aсимвол оповещения (звонка), как в C
\bвозврат на символ, как в C
\Bсиноним обратного слэша (\) для сокращения необходимости его удвоения
\cX(где X — любой символ) символ, чьи 5 младших битов такие же, как у X, а все остальные биты равны нулю
\eсимвол с именем последовательности сортировки ESC или, если это не так, символ с восьмеричным значением 033
\fподача формы, как в C
\nперевод строки, как в C
\rвозврат каретки, как в C
\tгоризонтальная табуляция, как в C
\uwxyz(где wxyz — ровно четыре шестнадцатеричные цифры) символ, шестнадцатеричное значение которого равно 0xwxyz
\Ustuvwxyz(где stuvwxyz — ровно восемь шестнадцатеричных цифр) символ, шестнадцатеричное значение которого равно 0xstuvwxyz
\vвертикальная табуляция, как в C
\xhhh(где hhh — любая последовательность шестнадцатеричных цифр) символ, шестнадцатеричное значение которого равно 0xhhh (один символ независимо от того, сколько шестнадцатеричных цифр используется)
\0символ, значение которого равно 0 (нулевой байт)
\xy(где xy — ровно две восьмеричные цифры, а не обратная ссылка) символ, восьмеричное значение которого равно 0xy
\xyz(где xyz — ровно три восьмеричных цифры, а не обратная ссылка) символ, восьмеричное значение которого равно 0xyz

Шестнадцатеричные цифры — это 0-9, a-f и A-F. Восьмеричные цифры — это 0-7.

Цифровые особые обозначения символов, задающие значения вне диапазона ASCII (0-127), меняют семантику в зависимости от кодировки базы данных. При кодировке UTF-8 управляющие значения равнозначны кодовым точкам Unicode, например, \u1234 означает символ U+1234. Для других многобайтовых кодировок особые обозначения символов обычно просто задают конкатенацию байтовых значений для символа. Если управляющее значение не соответствует никакому допустимому символу в кодировке базы данных, ошибки не возникнет, но это значение никогда не будет соответствовать никаким данным.

Особые обозначения символов всегда принимаются как обычные символы. Например, \135 является символом ] в ASCII, но \135 не завершает выражение в квадратных скобках.

Таблица 21. Коды классов в регулярных выражениях

Управляющий символОписание
\dсоответствует любой цифре; равнозначно [[:digit:]]
\sсоответствует любому пробельному символу; равнозначно [[:space:]]
\wсоответствует любому словообразующему символу; равнозначно [[:word:]]
\Dсоответствует любому нецифровому символу; равнозначно [^[:digit:]]
\Sсоответствует любому непробельному символу; равнозначно [^[:space:]]
\Wсоответствует любому несловообразующему символу; равнозначно [^[:word:]]

Коды классов также работают в выражениях в квадратных скобках, хотя показанные выше определения не вполне синтаксически допустимы в этом контексте. Например, выражение [a-c\d] равнозначно [a-c[:digit:]].

Таблица 22. Символы ограничений в регулярных выражениях

Управляющий символОписание
\Aсоответствует только началу строки (чем это отличается от ^, см. в подразделе Правила сопоставления регулярных выражений)
\mсоответствует только началу слова
\Mсоответствует только концу слова
\yсоответствует только началу или концу слова
\Yсоответствует только точке, которая не является началом или концом слова
\Zсоответствует только концу строки (чем это отличается от $, см. в подразделе Правила сопоставления регулярных выражений)

Слово определяется как в спецификации [[:<:]] и [[:>:]] выше. В выражениях в квадратных скобках символы ограничений недопустимы .

Таблица 23. Обратные ссылки в регулярных выражениях

Управляющий символОписание
\m(где m — ненулевая цифра) обратная ссылка на m-е подвыражение
\mnn(где m — ненулевая цифра, а nn — еще несколько цифр, и десятичное значение mnn не превышает число закрывающих захватывающих скобок, замеченных до сих пор) обратная ссылка на mnn-е подвыражение

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


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

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

RE может начинаться с одного из двух специальных префиксов-направителей. Если RE начинается с ***:, остальная его часть воспринимается как ARE. (Обычно в QHB это не имеет никакого значения, поскольку предполагается, что все RE являются ARE; но это имеет смысл, если параметром flags для функции regex был задан режим ERE или BRE). Если RE начинается с ***=, остальная его часть воспринимается как литеральная строка, причем все символы считаются обычными символами.

ARE может начинаться со встроенных параметров: последовательность (?xyz) (где xyz — один или несколько буквенных символов) задает параметры, влияющие на остальную часть RE. Эти параметры переопределяют любые ранее определенные параметры — в частности, они могут переопределять чувствительность к регистру, подразумеваемую оператором регулярного выражения, или параметр flags для функции регулярного выражения. Имеющиеся буквы параметров приведены в Таблице 24. Обратите внимание, что эти же буквы параметров используются в параметрах flags функций регулярных выражений.

Таблица 24. Буквы встроенных параметров ARE

ПараметрОписание
bостальная часть RE — BRE
cсопоставление с учетом регистра (переопределяет тип оператора)
eостальная часть RE — ERE
iсопоставление без учета регистра (см. подраздел Правила сопоставления регулярных выражений) (переопределяет тип оператора)
mисторический синоним для n
nсопоставление с учетом перевода строк (см. подраздел Правила сопоставления регулярных выражений)
pсопоставление с частичным учетом перевода строк (см. подраздел Правила сопоставления регулярных выражений)
qостальная часть RE является литеральной строкой («в кавычках»), все символы обычные
sсопоставление, не зависящее от перевода строки (по умолчанию)
tжесткий синтаксис (по умолчанию; см. ниже)
wобратное сопоставление с частичным учетом перевода строк («странное») (см. подраздел Правила сопоставления регулярных выражений)
xрасширенный синтаксис (см. ниже)

Встроенные параметры вступают в силу после символа ), завершающего последовательность. Они могут появляться только в начале ARE (после направителя ***: если таковой имеется).

В дополнение к обычному (строгому) синтаксису RE, в котором значимы все символы, существует расширенный синтаксис, доступный при указании встроенного параметра x. В расширенном синтаксисе символы пробела в RE игнорируются, как и все символы между знаком # и следующим переводом строки (или концом RE). Это позволяет создавать абзацы и комментировать сложные RE. Из этого основного правила есть три исключения:

  • пробельный символ или #, которому предшествует \, сохраняется

  • пробельный символ или # в выражении в квадратных скобках сохраняется

  • пробельный символ и комментарии не могут появляться в многосимвольных обозначениях, таких как (?:

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

Наконец, в ARE, вне выражений в квадратных скобках, последовательность (?#ttt) (где ttt - любой текст, не содержащий )) — это комментарий, который полностью игнорируется. Опять же, эта последовательность не допускается между символами многосимвольных обозначений, например (?:. Такие комментарии являются скорее историческим артефактом, чем полезным средством, и их использование не рекомендуется; вместо этого используйте расширенный синтаксис.

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


Правила сопоставления регулярных выражений

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

Является ли RE жадным или нет, определяется следующими правилами:

  • Большинство атомов и все ограничения не имеют атрибута жадности (поскольку они в любом случае не могут соответствовать переменным объемам текста).

  • Добавление скобок вокруг RE не влияет на его жадность.

  • Кванторный атом с квантификатором фиксированного повторения ({m} или {m}?) имеет такую же жадность (возможно, ее отсутствие), как сам атом.

  • Кванторный атом с другими нормальными квантификаторами (включая {m,n} с m равным n) является жадным (предпочитает самое длинное вхождение).

  • Кванторный атом с нежадным квантификатором (включая {m,n}? с m равным n) не является жадным (предпочитает самое короткое вхождение).

  • Ветвь — то есть RE, у которого нет оператора | на верхнем уровне — имеет ту же жадность, что и первый кванторный атом в ней, имеющий атрибут жадности.

  • RE, состоящее из двух или более ветвей, соединенных оператором |, всегда жадное.

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

Пример того, что это значит:

SELECT SUBSTRING('XY1234Z', 'Y*([0-9]{1,3})');
Result: 123
SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
Result: 1

В первом случае RE в целом жадное, потому что атом Y* жадный. Он может совпадать, начиная с Y, и соответствовать самой длинной из возможных строке, начинающейся там, то есть Y123. Выводимым результатом является ее часть в скобках, или 123. Во втором случае RE в целом нежадное, потому что атом Y*? нежадный. Он может совпадать, начиная с Y, и соответствовать самой короткой строке, начинающейся там, то есть Y1. Подвыражение [0-9]{1,3} является жадным, но не может изменить выбор относительно общей длины вхождения, поэтому ему приходится совпадать только с подстрокой 1.

Вкратце, когда RE содержит как жадные, так и нежадные подвыражения, все вхождение будет либо максимально длинным, либо максимально коротким, в соответствии с атрибутом, назначенным всему RE. Атрибуты, назначенные подвыражениям, влияют только на то, сколько из этого вхождения им разрешено «съесть» относительно друг друга.

Чтобы задать атрибут жадности или нежадности для подвыражения или целого RE, можно использовать квантификаторы {1,1} и {1,1}? соответственно. Это полезно, когда требуется, чтобы весь RE имел атрибут жадности, отличный от того, что выводится из его элементов. В качестве примера предположим, что мы пытаемся разделить строку, содержащую несколько цифр, на цифры и части до и после них. Мы можем попытаться сделать это так:

SELECT regexp_match('abc01234xyz', '(.*)(\d+)(.*)');
Result: {abc0123,4,xyz}

Это не сработало: первый атом .* жадный, поэтому он «съедает» столько, сколько может, оставляя \d+ совпадать с последним возможным местом, последней цифрой. Мы можем попытаться исправить это, сделав его нежадным:

SELECT regexp_match('abc01234xyz', '(.*?)(\d+)(.*)');
Result: {abc,0,""}

Это тоже не сработало, потому что теперь RE в целом нежадный, и поэтому он заканчивает все сравнение как можно скорее. Мы можем получить то, что хотим, заставив RE в целом быть жадным:

SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
Result: {abc,01234,xyz}

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

При принятии решения о том, какое вхождение длиннее или короче, длины вхождений измеряются в символах, а не в элементах сортировки. Пустая строка считается длиннее, чем отсутствие соответствия. Например: выражение bb* соответствует трем средним символам в строке abbbc; выражение (week|wee) (night|knights) — всем десяти символам в строке weeknights; когда выражение (.*).* сопоставляется со строкой abc, подвыражение в скобках соответствует всем трем символам; а когда выражение (a*)* сопоставляется со строкой bc, то и все RE, и подвыражение в скобках соответствуют пустой строке.

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

Если задано сопоставление с учетом перевода строк, атом . и выражения в скобках, использующие ^, никогда не будут соответствовать символу перевода строки (так что вхождения никогда не будут заходить за границу строки, если RE явно не включит эти символы), а ^ и $ будут соответствовать не только началу и концу строки соответственно, но и пустой строке после и до символа перевода строки соответственно. Однако управляющие символы ARE \A и \Z продолжают соответствовать только началу или концу строки. Кроме того, коды классов символов \D и \W будут соответствовать переводу строки независимо от этого режима. (В старых версиях QHB они не соответствовали переводу строки в режиме с учетом перевода строк. Для включения старого поведения напишите [^[:digit:]] или [^[:word:]].)

Если указано сопоставление с частичным учетом перевода строк, то перевод строки влияет на атом . и выражения в скобках, но не на ^ и $.

Если указано обратное сопоставление с частичным учетом перевода строк, то перевод строки влияет на ^ и $, но не на атом . и выражения в скобках. Это не очень полезно, но предусмотрено для симметрии.

Пределы и совместимость

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

Единственная особенность ARE, которая действительно несовместима с POSIX ERE, заключается в том, что \ не теряет своего особого значения в выражениях в квадратных скобках. Все остальные функциональные возможности ARE используют синтаксис, который является недопустимым или имеет эффекты, не определенные или не предусмотренные в POSIX ERE; синтаксис направителей *** также выходит за рамки синтаксиса POSIX как для BRE, так и для ERE.

Многие расширения ARE заимствованы из Perl, но некоторые были изменены в целях оптимизации, а некоторые расширения Perl отсутствуют. Заметные несовместимости включают в себя атомы \b, \B, отсутствие специальной обработки для завершающего перевода строки, добавление дополненных выражений в квадратных скобках в число случаев, на которые влияет сопоставление с учетом перевода строк, особые условия для круглых скобок и обратных ссылок в ограничениях просмотра вперед/назад, а также семантику «сопоставление самого длинного/самого короткого вхождения» (а не «первого вхождения»).


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

BRE отличаются от ERE в нескольких отношениях. В BRE |, + и ? являются обычными символами, и их функциональность не имеет аналогов. Разделителями для границ являются \{ и \}, причем сами по себе { и } — обычные символы. Скобками для вложенных подвыражений являются \( и \), а сами по себе ( и ) — обычные символы. ^ — обычный символ, если не стоит в начале RE или в начале подвыражения в скобках, $ — обычный символ, если не стоит в конце RE или в конце подвыражения в скобках, а * — обычный символ, если находится в начале RE или в начале подвыражения в скобках (возможно, после начального ^). Наконец, в BRE возможны обратные ссылки с одной цифрой, а \< и \> являются синонимами для [[:<:]] и [[:>:]] соответственно; в BRE нет других управляющих символов.


Отличия от XQuery (LIKE_REGEX)

Начиная с SQL:2008, стандарт SQL включает в себя оператор LIKE_REGEX, выполняющий сопоставление с шаблоном в соответствии со стандартом регулярных выражений XQuery. QHB еще не реализует этот оператор, но очень похожее поведение можно получить с помощью функции regexp_match(), поскольку регулярные выражения XQuery довольно близки к описанному выше синтаксису ARE.

Имеются заметные различия между существующей функцией регулярных выражений на основе POSIX и регулярными выражениями XQuery, в том числе:

  • Вычитание классов символов XQuery не поддерживается. Примером этой особенности является использование для сопоставление только с английскими согласными следующего выражения: [a-z-[aeiou]].

  • Коды классов символов XQuery \c, \C, \i и \I не поддерживаются.

  • Элементы классов символов XQuery, использующие \p{UnicodeProperty} или обратное \P{UnicodeProperty}, не поддерживаются.

  • В POSIX классы символов, такие как \w (см. Таблицу 21), интерпретируются в соответствии с преобладающей локалью (которой можно управлять, добавляя предложение COLLATE к оператору или функции). В XQuery эти классы определяются с помощью ссылок на свойства символов Unicode, поэтому равнозначное поведение возможно только с локалью, подчиняющейся правилам Unicode.

  • Стандарт SQL (не сам XQuery) пытается учесть больше вариантов «перевода строки», чем POSIX. Описанные выше варианты сопоставления с учетом перевода строк считают символом перевода строки только ASCII NL (\n), тогда как, следуя стандарту SQL, пришлось бы считать символами перевода строки также CR (\r), CRLF (\r\n) (перевод строки в стиле Windows) и некоторые символы, характерные только для Unicode, например LINE SEPARATOR (U+2028). Примечательно, что, согласно SQL, атомы . и \s должны считать последовательность \r\n одним символом, а не двумя.

  • Из особых обозначений символов, описанных в Таблице 20, XQuery поддерживает только \n, \r и \t.

  • XQuery не поддерживает синтаксис [:имя:] для классов символов в выражениях в квадратных скобках.

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

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

  • Буквы флагов регулярного выражения, определенные в XQuery, имеют нечто общее с буквами параметров для POSIX (Таблица 24), но отличаются них. Только параметры i и q одинаковы, остальные ведут себя совершенно по-другому:

  • Флаги XQuery s (разрешить соответствие точки переводу строки) и m (разрешить соответствие ^ и $ переводам строк) позволяют получить то же поведение, что и флаги POSIX n, p и w, но они не соответствуют поведению флагов POSIX s и m. В частности, обратите внимание, что по умолчанию точка соответствует переводу строки в POSIX, но не в XQuery.

  • Флаг XQuery x (игнорировать пробельные символы в шаблоне) заметно отличается от флага расширенного режима POSIX. В POSIX флаг x также допускает символ #, с которого начинается комментарий в шаблоне, и пробельный символ после обратного слэша в POSIX не игнорируется.