정규식
정규식 (Regular Expressions)
DuckDB는 [패턴 매칭 연산자]({% link docs/current/sql/functions/pattern_matching.md %}) ([LIKE]({% link docs/current/sql/functions/pattern_matching.md %}#like), [SIMILAR TO]({% link docs/current/sql/functions/pattern_matching.md %}#similar-to), [GLOB]({% link docs/current/sql/functions/pattern_matching.md %}#glob))뿐만 아니라 함수를 통한 정규식 지원도 제공해요.
출처: 문서
본문
정규식 문법 (Regular Expression Syntax)
DuckDB는 RE2 라이브러리를 정규식 엔진으로 사용해요. 정규식 문법에 대해서는 RE2 문서를 참고해요.
함수 (Functions)
모든 함수는 선택적 옵션 집합을 받아요.
| 이름 | 설명 |
|---|---|
regexp_extract(string, pattern[, group = 0][, options]) |
string이 정규식 pattern을 포함하면 선택적 파라미터 group이 지정한 캡처링 그룹을 반환하고, 그렇지 않으면 빈 문자열을 반환해요. group은 상수 값이어야 해요. group이 없으면 기본값 0이에요. 선택적 options 집합을 설정할 수 있어요. |
regexp_extract(string, pattern, name_list[, options]) |
string이 정규식 pattern을 포함하면 name_list의 이름에 대응하는 캡처링 그룹들을 struct로 반환하고, 그렇지 않으면 같은 키와 빈 문자열 값을 가진 struct를 반환해요. |
regexp_extract_all(string, regex[, group = 0][, options]) |
string에서 regex의 겹치지 않는 발생을 찾고 group에 해당하는 값을 반환해요. |
regexp_extract_all(string, regex, name_list[, options]) |
string에서 regex의 겹치지 않는 발생을 찾고 name_list의 이름에 대응하는 캡처링 그룹들을 struct 리스트로 반환해요. |
regexp_full_match(string, regex[, options]) |
전체 string이 regex와 일치하면 true를 반환해요. |
regexp_matches(string, pattern[, options]) |
string이 정규식 pattern을 포함하면 true, 그렇지 않으면 false를 반환해요. |
regexp_replace(string, pattern, replacement[, options]) |
string이 정규식 pattern을 포함하면 매치된 부분을 replacement로 교체해요. 기본적으로 첫 번째 발생만 교체돼요. 전역 플래그 g를 포함한 선택적 options 집합을 설정할 수 있어요. |
regexp_split_to_array(string, regex[, options]) |
string_split_regex의 별칭이에요. regex를 따라 string을 분할해요. |
regexp_split_to_table(string, regex[, options]) |
regex를 따라 string을 분할하고 각 부분에 대해 행을 반환해요. |
regexp_extract(string, pattern[, group = 0][, options])
| 설명 | string이 정규식 pattern을 포함하면 선택적 파라미터 group이 지정한 캡처링 그룹을 반환하고, 그렇지 않으면 빈 문자열을 반환해요. group은 상수 값이어야 해요. group이 없으면 기본값 0이에요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_extract('abc', '([a-z])(b)', 1) |
| 결과 | a |
regexp_extract(string, pattern, name_list[, options])
| 설명 | string이 정규식 pattern을 포함하면 name_list의 이름에 대응하는 캡처링 그룹들을 struct로 반환하고, 그렇지 않으면 같은 키와 빈 문자열 값을 가진 struct를 반환해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_extract('2023-04-15', '(\d+)-(\d+)-(\d+)', ['y', 'm', 'd']) |
| 결과 | {'y':'2023', 'm':'04', 'd':'15'} |
regexp_extract_all(string, regex[, group = 0][, options])
| 설명 | string에서 regex의 겹치지 않는 발생을 찾고 group에 해당하는 값을 반환해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_extract_all('Peter: 33, Paul:14', '(\w+):\s*(\d+)', 2) |
| 결과 | [33, 14] |
regexp_extract_all(string, regex, name_list[, options])
| 설명 | string에서 regex의 겹치지 않는 발생을 찾고 name_list의 이름에 대응하는 캡처링 그룹들을 struct 리스트로 반환해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_extract_all('Peter: 33, Paul: 14', '(\w+):\s*(\d+)', ['name', 'age']) |
| 결과 | [{'name': Peter, 'age': 33}, {'name': Paul, 'age': 14}] |
regexp_full_match(string, regex[, options])
| 설명 | 전체 string이 regex와 일치하면 true를 반환해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_full_match('anabanana', '(an)*') |
| 결과 | false |
regexp_matches(string, pattern[, options])
| 설명 | string이 정규식 pattern을 포함하면 true, 그렇지 않으면 false를 반환해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_matches('anabanana', '(an)*') |
| 결과 | true |
regexp_replace(string, pattern, replacement[, options])
| 설명 | string이 정규식 pattern을 포함하면 매치된 부분을 replacement로 교체해요. 기본적으로 첫 번째 발생만 교체돼요. 전역 플래그 g를 포함한 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_replace('hello', '[lo]', '-') |
| 결과 | he-lo |
regexp_split_to_array(string, regex[, options])
| 설명 | string_split_regex의 별칭이에요. regex를 따라 string을 분할해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_split_to_array('hello world; 42', ';? ') |
| 결과 | ['hello', 'world', '42'] |
regexp_split_to_table(string, regex[, options])
| 설명 | regex를 따라 string을 분할하고 각 부분에 대해 행을 반환해요. 선택적 options 집합을 설정할 수 있어요. |
| 예시 | regexp_split_to_table('hello world; 42', ';? ') |
| 결과 | 세 행: 'hello', 'world', '42' |
regexp_matches 함수는 SIMILAR TO 연산자와 비슷하지만, 전체 문자열이 일치할 것을 요구하지 않아요. 대신 regexp_matches는 문자열이 패턴을 포함하기만 하면 true를 반환해요 (정규식을 문자열의 시작과 끝에 고정하는 특수 토큰 ^와 $를 사용하지 않는 한). 몇 가지 예를 볼게요:
SELECT regexp_matches('abc', 'abc'); -- true
SELECT regexp_matches('abc', '^abc$'); -- true
SELECT regexp_matches('abc', 'a'); -- true
SELECT regexp_matches('abc', '^a$'); -- false
SELECT regexp_matches('abc', '.*(b|d).*'); -- true
SELECT regexp_matches('abc', '(b|c).*'); -- true
SELECT regexp_matches('abc', '^(b|c).*'); -- false
SELECT regexp_matches('abc', '(?i)A'); -- true
SELECT regexp_matches('abc', 'A', 'i'); -- true
정규식 함수 옵션 (Options for Regular Expression Functions)
정규식 함수는 다음 options를 지원해요.
| 옵션 | 설명 |
|---|---|
'c' |
대소문자 구분 매칭 |
'i' |
대소문자 구분 없는 매칭 |
'l' |
정규식 토큰 대신 리터럴 매칭 |
'm', 'n', 'p' |
개행 구분 매칭 |
'g' |
전역 교체, regexp_replace에서만 사용 가능 |
's' |
개행 구분 없는 매칭 |
예를 들어:
SELECT regexp_matches('abcd', 'ABC', 'c'); -- false
SELECT regexp_matches('abcd', 'ABC', 'i'); -- true
SELECT regexp_matches('ab^/$cd', '^/$', 'l'); -- true
SELECT regexp_matches(E'hello\nworld', 'hello.world', 'p'); -- false
SELECT regexp_matches(E'hello\nworld', 'hello.world', 's'); -- true
regexp_matches 사용
regexp_matches 연산자는 가능하면 LIKE 연산자로 최적화돼요. 최고 성능을 얻으려면 해당되는 경우 'c' 옵션(대소문자 구분 매칭)을 전달해야 해요. 기본적으로 RE2 라이브러리는 . 문자를 개행과 매치하지 않아요.
| 원본 | 최적화된 동등 형태 |
|---|---|
regexp_matches('hello world', '^hello', 'c') |
prefix('hello world', 'hello') |
regexp_matches('hello world', 'world$', 'c') |
suffix('hello world', 'world') |
regexp_matches('hello world', 'hello.world', 'c') |
LIKE 'hello_world' |
regexp_matches('hello world', 'he.*rld', 'c') |
LIKE '%he%rld' |
regexp_replace 사용
regexp_replace 함수는 정규식 패턴과 일치하는 문자열 부분을 교체 문자열로 바꾸는 데 사용해요. 교체 문자열에서 정규식으로 캡처된 그룹을 참조하려면 \d 표기법(d는 그룹을 나타내는 숫자)을 사용할 수 있어요. 기본적으로 regexp_replace는 정규식의 첫 번째 발생만 교체한다는 점을 참고해요. 모든 발생을 교체하려면 전역 교체(g) 플래그를 사용해요.
regexp_replace 사용 예시:
SELECT regexp_replace('abc', '(b|c)', 'X'); -- aXc
SELECT regexp_replace('abc', '(b|c)', 'X', 'g'); -- aXX
SELECT regexp_replace('abc', '(b|c)', '\1\1\1\1'); -- abbbbc
SELECT regexp_replace('abc', '(.*)c', '\1e'); -- abe
SELECT regexp_replace('abc', '(a)(b)', '\2\1'); -- bac
regexp_extract 사용
regexp_extract 함수는 정규식 패턴과 일치하는 문자열의 일부를 추출하는 데 사용해요.
패턴 내 특정 캡처링 그룹은 group 파라미터로 추출할 수 있어요. group을 지정하지 않으면 기본값 0으로, 전체 패턴으로 첫 번째 매치를 추출해요.
SELECT regexp_extract('abc', '.b.'); -- abc
SELECT regexp_extract('abc', '.b.', 0); -- abc
SELECT regexp_extract('abc', '.b.', 1); -- (empty)
SELECT regexp_extract('abc', '([a-z])(b)', 1); -- a
SELECT regexp_extract('abc', '([a-z])(b)', 2); -- b
regexp_extract 함수는 name_list 인자도 지원하는데, 이는 문자열의 LIST예요. name_list를 사용하면 regexp_extract가 해당 캡처 그룹들을 STRUCT의 필드로 반환해요:
SELECT regexp_extract('2023-04-15', '(\d+)-(\d+)-(\d+)', ['y', 'm', 'd']);
{'y': 2023, 'm': 04, 'd': 15}
SELECT regexp_extract('2023-04-15 07:59:56', '^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)', ['y', 'm', 'd']);
{'y': 2023, 'm': 04, 'd': 15}
SELECT regexp_extract('duckdb_0_7_1', '^(\w+)_(\d+)_(\d+)', ['tool', 'major', 'minor', 'fix']);
Binder Error:
Not enough group names in regexp_extract
열 이름의 개수가 캡처 그룹의 개수보다 적으면 첫 번째 그룹들만 반환돼요. 열 이름의 개수가 더 많으면 오류가 생성돼요.
제한 사항 (Limitations)
정규식은 캡처 그룹 9개만 지원해요: \1, \2, \3, ..., \9.
두 자리 이상의 캡처 그룹은 지원되지 않아요.
더 알아보기 (Learn more)
패턴 매칭 연산자 전반에 대해서는 [Pattern Matching]({% link docs/current/sql/functions/pattern_matching.md %}) 문서를 참고해요.