정규 표현식(regular expression)은 문자열에서 찾을 모양을 \d·+·^ 같은 기호로 적은 패턴입니다. Oracle은 REGEXP_LIKE 조건과 REGEXP_SUBSTR 같은 함수로 이 패턴을 씁니다.
LIKE는 %(아무 글자 0개 이상)와 _(아무 글자 하나)만 쓸 수 있어서 "숫자 3개, 하이픈, 숫자 4개, 하이픈, 숫자 4개" 같은 모양을 나타내기 어렵습니다.
"두 번째 숫자 덩어리만 꺼내기", "끝의 숫자 4개만 가리기"도 LIKE로는 할 수 없습니다.
아래 그림은 '010-1234-5678'의 글자 칸 13개를 패턴이 훑는 모습입니다.
1패턴이 문자열을 훑는 법
\d+는 숫자 한 글자(\d)가 한 번 이상(+) 이어진 덩어리입니다. 첫 글자 0부터 맞기 시작해 - 앞에서 멈추므로 첫 번째 일치는 010입니다.
두 번째 일치는 첫 번째 일치가 끝난 다음 글자부터 찾아 1234, 세 번째는 5678입니다. 일치끼리는 겹치지 않습니다.
패턴에는 다음 기호를 씁니다.
| 기호 | 뜻 | 예 |
|---|---|---|
. | 아무 글자 한 개(줄바꿈 빼고) | S.L은 SQL과 맞음 |
* · + · ? | 바로 앞의 것이 0번 이상 · 1번 이상 · 0번 또는 1번 | \d+ |
{m} · {m,} · {m,n} | 정확히 m번 · m번 이상 · m번 이상 n번 이하 | \d{4} |
^ · $ | 문자열의 시작 · 끝 | ^김 · \d{4}$ |
[ ] | 대괄호 안 글자 가운데 하나. -로 범위를 적음 | [윤연] · [0-9] |
[^ ] | 대괄호 안 글자가 아닌 글자 하나 | [^-] |
| | 또는 | 김|이 |
( ) | 묶음(하위 식). \1처럼 번호로 다시 가리킴 | (\d+)-(\d+) |
\d · \w · \s | 숫자 · 단어 글자 · 공백 한 글자. 대문자 \D · \W · \S는 그 반대 | \d |
[:digit:] | POSIX 문자 클래스(대괄호 안에 씀). [:alpha:] 등도 있음 | [[:digit:]] |
2REGEXP 함수와 인자
다섯 함수는 같은 패턴을 쓰고, 돌려주는 것만 다릅니다.
| 함수 | 돌려주는 것 | 일치가 없으면 |
|---|---|---|
| REGEXP_LIKE | 참·거짓(조건) | 거짓 |
| REGEXP_SUBSTR | 맞는 부분 | NULL |
| REGEXP_INSTR | 시작 위치 | 0 |
| REGEXP_COUNT | 일치 개수 | 0 |
| REGEXP_REPLACE | 바꾼 문자열 | 원래 문자열 |
REGEXP_LIKE는 값이 아니라 참·거짓을 내는 조건이라 WHERE나 CASE WHEN에 씁니다. Oracle 23부터는 SELECT 목록에도 쓸 수 있지만, 시험은 조건으로 다룹니다. REGEXP_SUBSTR의 인자는 다음 차례입니다.
REGEXP_SUBSTR(문자열, 패턴,
시작 위치, 몇 번째 일치,
일치 옵션)
\d+에 시작 위치 6을 주면 1234의 중간인 6번 글자부터 훑어 234가 나옵니다.
일치 옵션 'i'는 대소문자를 가리지 않고 'c'는 가립니다. 'n'은 .이 줄바꿈과도 맞게, 'm'은 ^·$가 줄마다 맞게 합니다.
REGEXP_INSTR의 다섯째 인자가 1이면 일치가 끝난 다음 위치를 돌려주고, REGEXP_SUBSTR의 여섯째 인자는 돌려줄 하위 식의 번호입니다.
REGEXP_REPLACE는 바꿀 문자열을 빼면 맞는 부분을 지우고, 바꿀 문자열 안의 \1·\2는 하위 식을 가리킵니다. REGEXP_REPLACE는 바꿀 문자열이 셋째 인자라 시작 위치·몇 번째 일치가 하나씩 밀리고, REGEXP_LIKE의 셋째 인자는 일치 옵션입니다.
3자리 기호와 길게 잡기
^와 $는 글자가 아니라 문자열의 시작과 끝 자리와 맞습니다.
\d{4}$에서 1234는 바로 뒤가 -라서 떨어지고 5678만 맞습니다. ^\d{3}-\d{4}-\d{4}$는 숫자가 하나 더 붙은 '010-1234-56789'와 맞지 않지만, ^·$를 빼면 문자열 안 어딘가에 그 모양이 있기만 하면 맞습니다.
^가 [^,]처럼 대괄호 안 맨 앞에 오면 시작 자리가 아니라 '이 글자들이 아닌 글자'입니다.
*·+는 되도록 많이 맞추는 쪽으로 잡습니다. .*-는 끝까지 늘었다가 되돌아와 마지막 -까지 010-1234-를 잡고, 뒤에 ?를 붙인 .*?-는 첫 -까지 010-만 잡습니다.
예제
일치가 3개뿐이라 네 번째 일치(M4)는 NULL입니다.
SELECT REGEXP_SUBSTR(
'010-1234-5678',
'\d+') AS M1,
REGEXP_SUBSTR(
'010-1234-5678',
'\d+', 1, 2) AS M2,
REGEXP_SUBSTR(
'010-1234-5678',
'\d+', 1, 3) AS M3,
REGEXP_SUBSTR(
'010-1234-5678',
'\d+', 1, 4) AS M4
FROM DUAL;
| M1 | M2 | M3 | M4 |
|---|---|---|---|
| 010 | 1234 | 5678 | NULL |
+가 있는 \d+는 덩어리를, +가 없는 \d는 숫자 한 글자를 셉니다.
SELECT REGEXP_INSTR(
'010-1234-5678',
'\d+', 1, 2) AS POS2,
REGEXP_COUNT(
'010-1234-5678',
'\d+') AS CNT,
REGEXP_COUNT(
'010-1234-5678',
'\d') AS DIGITS,
REGEXP_INSTR(
'010-1234-5678',
'x') AS NOPE
FROM DUAL;
| POS2 | CNT | DIGITS | NOPE |
|---|---|---|---|
| 5 | 3 | 11 | 0 |
SELECT REGEXP_REPLACE(
'010-1234-5678',
'\d{4}$', '****')
AS MASKED,
REGEXP_REPLACE(
'010-1234-5678',
'\d', '*') AS ALL_MASK,
REGEXP_REPLACE(
'010-1234-5678',
'-', '') AS NODASH
FROM DUAL;
| MASKED | ALL_MASK | NODASH |
|---|---|---|
010-1234-**** | ***-****-**** | 01012345678 |
LIKE 두 개를 OR로 잇는 대신, 성이 김이나 이인 사원을 패턴 하나로 찾습니다.
SELECT ENAME
FROM EMP
WHERE REGEXP_LIKE(
ENAME, '^(김|이)')
ORDER BY EMPNO;
| ENAME |
|---|
| 김민준 |
| 이서연 |
[^,]+는 '쉼표가 아닌 글자가 하나 이상'이라, 쉼표로 나뉜 목록에서 n번째 항목을 꺼낼 때 씁니다.
SELECT REGEXP_SUBSTR(
'김민준,이서연,박지호',
'[^,]+', 1, 2) AS NAME2
FROM DUAL;
| NAME2 |
|---|
| 이서연 |
시험 포인트
^는 대괄호 밖에서는 문자열의 시작,[^…]처럼 대괄호 안 맨 앞에서는 '이 글자들이 아닌 글자'입니다.*0번 이상 ·+1번 이상 ·?0번 또는 1번입니다.*·+는 길게,*?·+?는 짧게 잡습니다.- 일치가 없으면 REGEXP_SUBSTR는 NULL, REGEXP_INSTR·REGEXP_COUNT는 0입니다. REGEXP_LIKE는 조건이라 WHERE에 씁니다.
- REGEXP_SUBSTR·REGEXP_INSTR의 셋째 인자는 시작 위치, 넷째 인자는 몇 번째 일치이고(REGEXP_REPLACE는 하나씩 밀림), 다음 일치는 앞 일치가 끝난 뒤부터 찾습니다.
- 일치 옵션
'i'는 대소문자를 가리지 않고,'c'는 가립니다.
확인 문제
1. 다음 세 값은 무엇일까요?
SELECT REGEXP_SUBSTR(
'SQLD-2026-10-12',
'\d+', 1, 2) AS PART2,
REGEXP_SUBSTR(
'SQLD-2026-10-12',
'\d+', 1, 3) AS PART3,
REGEXP_COUNT(
'SQLD-2026-10-12',
'\d+') AS CNT
FROM DUAL;
정답
10, 12, 3입니다.
| PART2 | PART3 | CNT |
|---|---|---|
| 10 | 12 | 3 |
SQLD는 숫자가 아니라 일치에 들지 않습니다. 숫자 덩어리는 2026, 10, 12 셋이라 두 번째가 10, 세 번째가 12입니다.
2. 다음 쿼리는 몇 명을 고를까요? 두 ^의 뜻을 갈라 보세요.
SELECT ENAME
FROM EMP
WHERE REGEXP_LIKE(
ENAME, '^[^김이]')
ORDER BY EMPNO;
정답
4명입니다.
| ENAME |
|---|
| 박지호 |
| 최유나 |
| 정하늘 |
| 강도윤 |
앞의 ^는 문자열의 시작, 대괄호 안의 ^는 '김·이가 아닌 글자'입니다. 그래서 첫 글자가 김도 이도 아닌 사원을 고릅니다.
3. 다음 쿼리의 결과는 무엇일까요?
SELECT REGEXP_REPLACE(
'010-1234-5678',
'(\d+)-(\d+)-(\d+)',
'\3-\2-\1') AS SWAPPED
FROM DUAL;
정답
5678-1234-010입니다.
| SWAPPED |
|---|
| 5678-1234-010 |
괄호로 묶은 세 덩어리가 차례로 \1(010), \2(1234), \3(5678)이 되고, 바꿀 문자열 '\3-\2-\1'이 이 셋을 거꾸로 잇습니다.