REGEXP_EXTRACT
설명
주어진 문자열 STR에 정규식 매칭을 수행하여 지정된 패턴과 일치하는 POS번째 부분을 추출하는 함수입니다. 함수가 일치 결과를 반환하려면 패턴이 STR의 일부와 정확히 일치해야 합니다.
일치하는 부분을 찾지 못하면 빈 문자열을 반환합니다. 문자 집합 매칭을 처리할 때는 Utf-8 표준 문자 클래스를 사용해야 합니다. 이를 통해 함수가 여러 언어의 다양한 문자를 올바르게 인식하고 처리할 수 있습니다.
str 매개변수는 'string' 타입이며, 정규식 매칭을 수행할 문자열을 나타냅니다.
pattern 매개변수는 'string' 타입이며, 대상 정규 표현식 패턴을 나타냅니다.
pos 매개변수는 'integer' 타입이며, 문자열에서 정규 표현식 일치 검색을 시작할 위치를 지정합니다. 위치는 1부터 시작하며, 이 매개변수는 반드시 지정해야 합니다.
pattern이 유효한 정규 표현식이 아니면 오류가 발생합니다.
기본적으로 지원되는 문자 매칭 클래스: https://github.com/google/re2/wiki/Syntax
Doris에서는 세션 변수 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'가 오고 다시 하나 이상의 소문자가 이어지는 문자열 부분과 일치합니다. 'C' 앞의 첫 번째 캡처 그룹 ([[:lower:]]+)는 'b'와 일치하므로 결과는 'b'입니다.
mysql> SELECT regexp_extract('AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 1);
+-------------------------------------------------------------+
| regexp_extract('AbCdE', '([[:lower:]]+)C([[:lower:]]+)', 1) |
+-------------------------------------------------------------+
| b |
+-------------------------------------------------------------+
두 번째로 일치하는 부분을 추출합니다. 여기서는 'C' 뒤의 두 번째 캡처 그룹 ([[:lower:]]+)가 '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 |
+--------+------------+