Перейти к содержимому
Последнее обновление

REGEXP_EXTRACT

Описание​

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

Если совпадений нет, возвращается пустая строка. При сопоставлении наборов символов следует использовать стандартные классы символов Utf-8. Это позволяет функциям правильно распознавать и обрабатывать символы разных языков.

Параметр str имеет тип 'string' и задаёт строку, в которой выполняется поиск по регулярному выражению. Параметр pattern имеет тип 'string' и задаёт искомое регулярное выражение. Параметр pos имеет тип 'integer' и задаёт позицию в строке, с которой начинается поиск совпадения с регулярным выражением. Отсчёт позиций начинается с 1; этот параметр обязателен.

Если pattern содержит недопустимое регулярное выражение, возникает ошибка.

Классы символов, поддерживаемые по умолчанию: https://github.com/google/re2/wiki/Syntax

Doris позволяет включить расширенные возможности регулярных выражений, например проверки окружения нулевой ширины (look-around), с помощью переменной сеанса enable_extended_regex (значение по умолчанию: false).

Типы сопоставления символов, поддерживаемые при установке переменной сеанса enable_extended_regex в true: https://www.boost.org/doc/libs/latest/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html

Синтаксис​

REGEXP_EXTRACT(<str>, <pattern>, <pos>)

Параметры​

ПараметрОписание
<str>Столбец, в котором нужно выполнить поиск по регулярному выражению. Имеет тип 'string'.
<pattern>Искомое регулярное выражение. Имеет тип 'string'.
<pos>Параметр, задающий позицию в строке, с которой начинается поиск совпадения с регулярным выражением. Это целое число, обозначающее позицию символа в строке (начиная с 1). Параметр pos обязателен.

Возвращаемое значение​

Часть строки, соответствующая шаблону. Имеет тип Varchar. Если совпадений нет, возвращается пустая строка.

Поведение по умолчанию:

Настройка по умолчаниюПоведение
. соответствует символу новой строкиПо умолчанию . может соответствовать \n (символу новой строки).
Учёт регистраПоиск совпадений выполняется с учётом регистра.
^/$ соответствуют границам всей строки^ соответствует только началу строки, $ соответствует только её концу, а не началу или концу отдельных строк.
Жадные квантификаторыПо умолчанию *, + и другие квантификаторы захватывают как можно больше символов.
UTF-8Строки обрабатываются в кодировке UTF-8.

Модификаторы шаблона:

Изменить поведение по умолчанию можно, добавив в начало pattern модификатор (?flags). Можно объединять несколько модификаторов, например (?im); префикс - отключает соответствующий параметр, например (?-s).

Модификаторы шаблона действуют только при использовании стандартного движка регулярных выражений. Если включён enable_extended_regex=true и используются проверки нулевой ширины (например, (?<=...), (?=...)), запрос обрабатывается движком Boost.Regex, и модификаторы могут вести себя не так, как ожидается. Рекомендуется не сочетать эти возможности.

ФлагЗначение
(?i)Поиск совпадений без учёта регистра
(?-i)Поиск с учётом регистра (по умолчанию)
(?s). соответствует символу новой строки (включено по умолчанию)
(?-s). не соответствует символу новой строки
(?m)Многострочный режим: ^ соответствует началу каждой строки, $ соответствует концу каждой строки
(?-m)Однострочный режим: ^/$ соответствуют границам всей строки (по умолчанию)
(?U)Нежадные квантификаторы: *, + и другие захватывают как можно меньше символов
(?-U)Жадные квантификаторы (по умолчанию): *, + и другие захватывают как можно больше символов

Пример​

Извлечение первой совпавшей части. В этом примере регулярное выражение ([[:lower:]]+)C([[:lower:]]+) соответствует фрагменту строки, в котором после одной или нескольких строчных букв следует 'C', а затем одна или несколько строчных букв. Первая захватывающая группа ([[:lower:]]+) перед 'C' соответствует 'b', поэтому результатом будет 'b'.

mysql> SELECT regexp_extract('AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 1);
+-------------------------------------------------------------+
| regexp_extract('AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 1) |
+-------------------------------------------------------------+
| b |
+-------------------------------------------------------------+

Извлечение второй совпавшей части. Здесь вторая захватывающая группа ([[:lower:]]+) после 'C' соответствует 'd', поэтому результатом будет 'd'.

mysql> SELECT regexp_extract('AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 2);
+-------------------------------------------------------------+
| regexp_extract('AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 2) |
+-------------------------------------------------------------+
| d |
+-------------------------------------------------------------+

Поиск китайских символов. Шаблон (\p{Han}+)(.+) сначала сопоставляется с одним или несколькими китайскими символами (\p{Han}+), а затем с оставшейся частью строки ((.+)). Вторая захватывающая группа соответствует части строки без китайских символов, поэтому результатом будет 'This is a passage in English 1234567'.

mysql> select regexp_extract('这是一段中文 This is a passage in English 1234567', '(\\p{Han}+)(.+)', 2);
+-----------------------------------------------------------------------------------------------+
| regexp_extract('这是一段中文 This is a passage in English 1234567', '(\p{Han}+)(.+)', 2) |
+-----------------------------------------------------------------------------------------------+
| This is a passage in English 1234567 |
+-----------------------------------------------------------------------------------------------+

Вставка значений переменных и поиск совпадений. В этом примере данные вставляются в таблицу, а затем функция REGEXP_EXTRACT извлекает совпавшие части сохранённых строк на основе сохранённых шаблонов и позиций.


CREATE TABLE test_table_for_regexp_extract (
id INT,
text_data VARCHAR(500),
pattern VARCHAR(100),
pos INT
) PROPERTIES ("replication_num"="1");

INSERT INTO test_table_for_regexp_extract VALUES
(1, 'AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 1),
(2, 'AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 2),
(3, '这是一段中文 This is a passage in English 1234567', '(\\p{Han}+)(.+)', 2);

SELECT id, regexp_extract(text_data, pattern, pos) as extract_result FROM test_table_for_regexp_extract ORDER BY id;

+------+----------------+
| id | extract_result |
+------+----------------+
| 1 | b |
| 2 | d |
| 3 | This is a passage in English 1234567 |
+------+----------------+

Проверка с шаблоном, для которого нет совпадений. Поскольку шаблон ([[:digit:]]+) (одна или несколько цифр) не соответствует ни одной части строки 'AbCdE', возвращается пустая строка.

SELECT regexp_extract('AbCdE', '([[:digit:]]+)', 1);
+------------------------------------------------+
| regexp_extract('AbCdE', '([[:digit:]]+)', 1) |
+------------------------------------------------+
| |
+------------------------------------------------+

Пример с эмодзи

SELECT regexp_extract('Text 😊 More 😀', '😊|😀',0);

+------------------------------------------------------+
| regexp_extract('Text 😊 More 😀', '😊|😀',0) |
+------------------------------------------------------+
| 😊 |
+------------------------------------------------------+

Если 'str' имеет значение NULL, возвращается NULL

mysql> SELECT REGEXP_EXTRACT(NULL, '([a-z]+)', 1);
+-------------------------------------+
| REGEXP_EXTRACT(NULL, '([a-z]+)', 1) |
+-------------------------------------+
| NULL |
+-------------------------------------+

Если 'pattern' имеет значение NULL, возвращается NULL

mysql> SELECT REGEXP_EXTRACT('Hello World', NULL, 1);
+----------------------------------------+
| REGEXP_EXTRACT('Hello World', NULL, 1) |
+----------------------------------------+
| NULL |
+----------------------------------------+

Если 'pos' имеет значение NULL, возвращается NULL

mysql> SELECT REGEXP_EXTRACT('Hello World', '([a-z]+)', NULL);
+-------------------------------------------------+
| REGEXP_EXTRACT('Hello World', '([a-z]+)', NULL) |
+-------------------------------------------------+
| NULL |
+-------------------------------------------------+

Если все параметры имеют значение NULL, возвращается NULL

mysql> SELECT REGEXP_EXTRACT(NULL, NULL, NULL);
+----------------------------------+
| REGEXP_EXTRACT(NULL, NULL, NULL) |
+----------------------------------+
| NULL |
+----------------------------------+

Если pattern содержит недопустимое регулярное выражение, возникает ошибка.

SELECT regexp_extract('AbCdE', '([[:digit:]]+', 1);
ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.2)[INVALID_ARGUMENT]Could not compile regexp pattern: ([[:digit:]]+
Error: missing ): ([[:digit:]]+

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

SELECT regexp_extract('foo123bar456baz', '(?<=foo)(\\d+)(?=bar)', 1);
-- ERROR 1105 (HY000): errCode = 2, detailMessage = (127.0.0.1)[INVALID_ARGUMENT]Invalid regex pattern: (?<=foo)(\d+)(?=bar). Error: invalid perl operator: (?<
SET enable_extended_regex = true;
SELECT regexp_extract('foo123bar456baz', '(?<=foo)(\\d+)(?=bar)', 1);
+---------------------------------------------------------------+
| regexp_extract('foo123bar456baz', '(?<=foo)(\\d+)(?=bar)', 1) |
+---------------------------------------------------------------+
| 123 |
+---------------------------------------------------------------+

Модификаторы шаблона

Поиск без учёта регистра: (?i) позволяет игнорировать регистр при сопоставлении

SELECT REGEXP_EXTRACT('Hello World', '(hello)', 1) AS case_sensitive,
REGEXP_EXTRACT('Hello World', '(?i)(hello)', 1) AS case_insensitive;
+----------------+------------------+
| case_sensitive | case_insensitive |
+----------------+------------------+
| | Hello |
+----------------+------------------+

По умолчанию . соответствует символу новой строки; используйте (?-s), чтобы . не соответствовал символу новой строки

SELECT REGEXP_EXTRACT('foo\nbar', '^(.+)$', 1) AS dot_match_nl,
REGEXP_EXTRACT('foo\nbar', '(?-s)^(.+)$', 1) AS dot_not_match_nl;
+--------------+------------------+
| dot_match_nl | dot_not_match_nl |
+--------------+------------------+
| foo
bar | |
+--------------+------------------+

Многострочный режим: (?m) позволяет ^ и $ соответствовать началу и концу каждой строки

SELECT REGEXP_EXTRACT('foo\nbar', '^(bar)', 1) AS single_line,
REGEXP_EXTRACT('foo\nbar', '(?m)^(bar)', 1) AS multi_line;
+-------------+------------+
| single_line | multi_line |
+-------------+------------+
| | bar |
+-------------+------------+

Жадный и нежадный поиск: (?U) заставляет квантификаторы захватывать как можно меньше символов

SELECT REGEXP_EXTRACT('aXbXc', '(a.*X)', 1) AS greedy,
REGEXP_EXTRACT('aXbXc', '(?U)(a.*X)', 1) AS non_greedy;
+--------+------------+
| greedy | non_greedy |
+--------+------------+
| aXbX | aX |
+--------+------------+