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 |
+--------+------------+