REGEXP_EXTRACT_ALL
Описание
Функция REGEXP_EXTRACT_ALL выполняет поиск по регулярному выражению в заданной строке str и извлекает все фрагменты, соответствующие первому подшаблону указанного шаблона pattern. Функция возвращает строку, представляющую совпавшую часть шаблона, при этом шаблон должен точно соответствовать некоторому фрагменту входной строки str. Если совпадений нет или шаблон не содержит подшаблонов, возвращается пустая строка.
При поиске совпадений с наборами символов следует использовать стандартные классы символов Utf-8. Это позволяет функциям правильно распознавать и обрабатывать символы разных языков.
Если '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_ALL(<str>, <pattern>)
Параметры
| Параметр | Описание |
|---|---|
<str> | Параметр типа String. Задаёт входную строку, в которой будет выполняться поиск по регулярному выражению. Это может быть строковый литерал или ссылка на столбец таблицы, содержащий строковые данные. |
<pattern> | Этот параметр также имеет тип String. Задаёт шаблон регулярного выражения для сопоставления с входной строкой |
Возвращаемое значение
Возвращает NULL, если хотя бы один из аргументов равен NULL.
Функция возвращает строку, представляющую часть входной строки, которая соответствует первому подшаблону указанного регулярного выражения. Тип возвращаемого значения: String. Если совпадений нет или шаблон не содержит подшаблонов, возвращается пустая строка.
Поведение по умолчанию:
| Настройка по умолчанию | Поведение |
|---|---|
. соответствует переводу строки | По умолчанию . может соответствовать \n (переводу строки). |
| С учётом регистра | При поиске совпадений учитывается регистр. |
^/$ соответствуют границам всей строки | ^ соответствует только началу строки, а $ только её концу, а не началу и концу отдельных строк текста. |
| Жадные квантификаторы | По умолчанию *, + и другие квантификаторы захватывают как можно больше символов. |
| UTF-8 | Строки обрабатываются в кодировке UTF-8. |
Модификаторы шаблона:
Поведение по умолчанию можно изменить, добавив перед шаблоном pattern конструкцию (?flags). Несколько модификаторов можно объединять, например (?im); префикс - отключает соответствующую настройку, например (?-s).
Модификаторы шаблона действуют только при использовании стандартного движка регулярных выражений. Если включён enable_extended_regex=true и используются утверждения нулевой ширины (например, (?<=...), (?=...)), запрос обрабатывается движком Boost.Regex, и модификаторы могут работать не так, как ожидается. Рекомендуется не сочетать эти возможности.
| Флаг | Значение |
|---|---|
(?i) | Поиск совпадений без учёта регистра |
(?-i) | Поиск совпадений с учётом регистра (по умолчанию) |
(?s) | . соответствует переводу строки (включено по умолчанию) |
(?-s) | . не соответствует переводу строки |
(?m) | Многострочный режим: ^ соответствует началу каждой строки, а $ концу каждой строки |
(?-m) | Однострочный режим: ^/$ соответствуют границам всей строки (по умолчанию) |
(?U) | Нежадные квантификаторы: *, + и другие квантификаторы захватывают как можно меньше символов |
(?-U) | Жадные квантификаторы (по умолчанию): *, + и другие квантификаторы захватывают как можно больше символов |
Пример
Базовый поиск строчных букв вокруг 'C'. В этом примере шаблон ([[:lower:]]+)C([[:lower:]]+) соответствует фрагменту строки, в котором за одной или несколькими строчными буквами следует 'C', а затем ещё одна или несколько строчных букв. Первый подшаблон ([[:lower:]]+) перед 'C' соответствует 'b', поэтому результатом будет ['b'].
SELECT regexp_extract_all('AbCdE', '([[:lower:]]+)C([[:lower:]]+)');
+--------------------------------------------------------------+
| regexp_extract_all('AbCdE', '([[:lower:]]+)C([[:lower:]]+)') |
+--------------------------------------------------------------+
| ['b'] |
+--------------------------------------------------------------+
Несколько совпадений в строке. Здесь шаблон соответствует двум фрагментам строки. В первом совпадении первый подшаблон соответствует 'b', а во втором совпадении первый подшаблон соответствует 'f'. Поэтому результатом будет ['b', 'f'].
SELECT regexp_extract_all('AbCdEfCg', '([[:lower:]]+)C([[:lower:]]+)');
+-----------------------------------------------------------------+
| regexp_extract_all('AbCdEfCg', '([[:lower:]]+)C([[:lower:]]+)') |
+-----------------------------------------------------------------+
| ['b','f'] |
+-----------------------------------------------------------------+
Извлечение ключей из пар «ключ — значение». Шаблон соответствует парам «ключ — значение» в строке. Первый подшаблон захватывает ключи, поэтому результатом будет ['abc', 'def', 'ghi'].
SELECT regexp_extract_all('abc=111, def=222, ghi=333','("[^"]+"|\\w+)=("[^"]+"|\\w+)');
+--------------------------------------------------------------------------------+
| regexp_extract_all('abc=111, def=222, ghi=333', '("[^"]+"|\w+)=("[^"]+"|\w+)') |
+--------------------------------------------------------------------------------+
| ['abc','def','ghi'] |
+--------------------------------------------------------------------------------+
Поиск китайских иероглифов. Шаблон (\p{Han}+)(.+) сначала сопоставляет один или несколько китайских иероглифов с первым подшаблоном (\p{Han}+), поэтому результатом будет ['这是一段中文'].
select regexp_extract_all('这是一段中文 This is a passage in English 1234567', '(\\p{Han}+)(.+)');
+------------------------------------------------------------------------------------------------+
| regexp_extract_all('这是一段中文 This is a passage in English 1234567', '(\p{Han}+)(.+)') |
+------------------------------------------------------------------------------------------------+
| ['这是一段中文'] |
+------------------------------------------------------------------------------------------------+
Вставка данных и использование REGEXP_EXTRACT_ALL
CREATE TABLE test_regexp_extract_all (
id INT,
text_content VARCHAR(255),
pattern VARCHAR(255)
) PROPERTIES ("replication_num"="1");
INSERT INTO test_regexp_extract_all VALUES
(1, 'apple1, banana2, cherry3', '([a-zA-Z]+)\\d'),
(2, 'red#123, blue#456, green#789', '([a-zA-Z]+)#\\d+'),
(3, 'hello@example.com, world@test.net', '([a-zA-Z]+)@');
SELECT id, regexp_extract_all(text_content, pattern) AS extracted_data
FROM test_regexp_extract_all;
+------+----------------------+
| id | extracted_data |
+------+----------------------+
| 1 | ['apple', 'banana', 'cherry'] |
| 2 | ['red', 'blue', 'green'] |
| 3 | ['hello', 'world'] |
+------+----------------------+
Если совпадений нет, возвращается пустая строка
SELECT REGEXP_EXTRACT_ALL('ABC', '(\\d+)');
+-------------------------------------+
| REGEXP_EXTRACT_ALL('ABC', '(\\d+)') |
+-------------------------------------+
| |
+-------------------------------------+
Поиск эмодзи
SELECT REGEXP_EXTRACT_ALL('👩💻,👨🚀', '(💻|🚀)');
+--------------------------------------------------------------+
| REGEXP_EXTRACT_ALL('👩💻,👨🚀', '(💻|🚀)') |
+--------------------------------------------------------------+
| ['💻','🚀'] |
+--------------------------------------------------------------+
Если 'Str' равен NULL, возвращается NULL
SELECT regexp_extract_all(NULL, '([a-z]+)');
+--------------------------------------+
| regexp_extract_all(NULL, '([a-z]+)') |
+--------------------------------------+
| NULL |
+--------------------------------------+
Если 'pattern' равен NULL, возвращается NULL
SELECT regexp_extract_all('Hello World', NULL);
+-----------------------------------------+
| regexp_extract_all('Hello World', NULL) |
+-----------------------------------------+
| NULL |
+-----------------------------------------+
Если все параметры равны NULL, возвращается NULL
SELECT regexp_extract_all(NULL,NULL);
+-------------------------------+
| regexp_extract_all(NULL,NULL) |
+-------------------------------+
| NULL |
+-------------------------------+
Если pattern содержит недопустимое регулярное выражение, возникает ошибка.
SELECT regexp_extract_all('hello (world) 123', '([[:alpha:]+');
ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.2)[INVALID_ARGUMENT]Could not compile regexp pattern: ([[:alpha:]+
Error: missing ]: [[:alpha:]+
Расширенные регулярные выражения
SELECT REGEXP_EXTRACT_ALL('ID:AA-1,ID:BB-2,ID:CC-3', '(?<=ID:)([A-Z]{2}-\\d)');
ERROR 1105 (HY000): errCode = 2, detailMessage = (127.0.0.1)[INVALID_ARGUMENT]Invalid regex pattern: (?<=ID:)([A-Z]{2}-\d). Error: invalid perl operator: (?<
SET enable_extended_regex = true;
SELECT REGEXP_EXTRACT_ALL('ID:AA-1,ID:BB-2,ID:CC-3', '(?<=ID:)([A-Z]{2}-\\d)');
+-------------------------------------------------------------------------+
| REGEXP_EXTRACT_ALL('ID:AA-1,ID:BB-2,ID:CC-3', '(?<=ID:)([A-Z]{2}-\\d)') |
+-------------------------------------------------------------------------+
| ['AA-1','BB-2','CC-3'] |
+-------------------------------------------------------------------------+
Модификаторы шаблона
Поиск без учёта регистра: (?i) позволяет игнорировать регистр при поиске совпадений
SELECT REGEXP_EXTRACT_ALL('Hello hello HELLO', '(hello)') AS case_sensitive,
REGEXP_EXTRACT_ALL('Hello hello HELLO', '(?i)(hello)') AS case_insensitive;
+----------------+---------------------------+
| case_sensitive | case_insensitive |
+----------------+---------------------------+
| ['hello'] | ['Hello','hello','HELLO'] |
+----------------+---------------------------+
Многострочный режим: (?m) заставляет ^ и $ соответствовать началу и концу каждой строки
SELECT REGEXP_EXTRACT_ALL('foo\nbar\nbaz', '^([a-z]+)') AS single_line,
REGEXP_EXTRACT_ALL('foo\nbar\nbaz', '(?m)^([a-z]+)') AS multi_line;
+-------------+---------------------+
| single_line | multi_line |
+-------------+---------------------+
| ['foo'] | ['foo','bar','baz'] |
+-------------+---------------------+
Жадные и нежадные квантификаторы: (?U) заставляет квантификаторы захватывать как можно меньше символов
SELECT REGEXP_EXTRACT_ALL('aXbXcXd', '(a.*X)') AS greedy,
REGEXP_EXTRACT_ALL('aXbXcXd', '(?U)(a.*X)') AS non_greedy;
+----------+------------+
| greedy | non_greedy |
+----------+------------+
| ['aXbXcX'] | ['aX'] |
+----------+------------+