본문 바로가기
개발/오라클

오라클 - 정규표현식 함수 REGEXP_REPLACE()

by 루 프란체 2018. 4. 1.

오라클 정규표현식 함수 복습 제 2탄은 REGEXP_REPLACE() 되겠다.

정규식은 참 공부하면 공부할수록 쓸 일도 많고 아주 좋고 훌륭한 녀석인 것 같다.


REPLACE 가 단순하게 글자와 글자를 비교해 치환을 해준다면 REGEXP_REPLACE 또한 REGEXP_SUBSTR 과 마찬가지로 

정규식을 이용해 좀 더 다양하고 자세한 패턴으로 문자열을 검색, 변경할 수 있다.


우선은 간단한 것부터 예를 들어서 해보자. 기본 문법은 아래와 같다.

REGEXP_REPLACE(COLUMN, [REG_EXP], [REPLACE_STR], [START_INDEX], [REPLACE_INDEX])

/* 기본적인 사용 방법 */
SELECT REGEXP_REPLACE('안녕하세요., 반갑습니다./', '\..', '.') FROM DUAL;

/* 시작 INDEX 를 추가 */
SELECT REGEXP_REPLACE('안녕하세요., 반갑습니다./', '\..', '.', 10) FROM DUAL;

/* REPLACE 를 시도할 그룹 선언 (1번 그룹) */
SELECT REGEXP_REPLACE('안녕하세요., 반갑습니다./', '\..', '.', 1, 1) FROM DUAL;

/* REPLACE 를 시도할 그룹 선언 (2번 그룹) */
SELECT REGEXP_REPLACE('안녕하세요., 반갑습니다./', '\..', '.', 1, 2) FROM DUAL;

기본적인 사용방법은 기존의 REPLACE 와 크게 차이가 나지 않는다. 

오히려 굳이 이런 간단한 글자를 바꾸려고 이렇게 복잡하게 해야 하나 싶을 정도다.


시작 INDEX 를 추가하게 되면 주어진 문구 혹은 컬럼 값의 해당 INDEX 부터 REPLACE 를 시도한다.

위의 예제에서는 반갑습니다./ 만 반갑습니다. 로 치환 되어 표시될 것이다.


그룹 INDEX 를 선언하게 되면 해당 정규식으로 매핑되는 문자열들 중 선언한 INDEX 의 문구만 수정이 된다.

즉, 1번 그룹을 선언한 쿼리는 안녕하세요., 가 치환이 될 것이고 2번 그룹을 선언한 쿼리는 반갑습니다./ 만 치환이 될 것이다.


이 정도면 대략적인 사용 방법은 눈에 들어올 것이니 조금 더 복잡하게 선언을 해보자.

CREATE TABLE MUSIC_LIST
	(
    	MP3_NAME VARCHAR2(100)
    );
    
INSERT INTO MUSIC_LIST VALUES('터보 - 검은고양이 네로.mp3');
INSERT INTO MUSIC_LIST VALUES('[버즈] - 나에게로 떠나는 여행.mp3');
INSERT INTO MUSIC_LIST VALUES('(소녀시대) - 다시 만난 세계.mp3');
COMMIT;

SELECT	MP3_NAME
		, REGEXP_REPLACE(MP3_NAME, '[([]?([a-zA-Z가-힣0-9 ]+)[])]?\s-\s([a-zA-Z가-힣0-9 ]+)', '[\2] Song by \1')
        , REGEXP_REPLACE(MP3_NAME, '[([]?([a-zA-Z가-힣0-9 ]+)[])]?\s-\s([a-zA-Z가-힣0-9 ]+)', '\2 - \1')
FROM	MUSIC_LIST;

선곡은 아재라 죄송;

어쨌든 좀 조잡하게 작성을 했는데 위와 같은 방식으로도 사용이 가능하다는 것이다.


첫번째 정규식인 REGEXP_REPLACE(MP3_NAME, '[([]?([a-zA-Z가-힣0-9 ]+)[])]?\s-\s([a-zA-Z가-힣0-9 ]+)', '[\2] Song by \1') 은 

[노래명] Song by 가수명으로 치환되어 결과가 표시될 것이고... 


두번째 정규식인 REGEXP_REPLACE(MP3_NAME, '[([]?([a-zA-Z가-힣0-9 ]+)[])]?\s-\s([a-zA-Z가-힣0-9 ]+)', '\2 - \1') 은 

괄호, 대괄호는 제외하고 가수명과 노래명을 뒤바꿔 결과를 표시해줄 것이다.


그럼 여기서 아직 설명을 하지 않은 부분인데 \1, \2 는 무엇이냐면 REGEXP_REPLACE 사용시에 그룹으로 묶여있는 표현식이 있다면 

해당 그룹은 \1, \2, \3... 순으로 INDEX 를 사용해 표시할 수 있다.


이것도 간단한 예제를 들어 알아보자!

/* 띄어쓰기로 알아보는 정규식 그룹 예제 */
SELECT REGEXP_REPLACE('띄어쓰기로 알아보는 정규식 그룹 예제입니다', '([가-힣]+) ', '\1.') FROM DUAL;

/* 전화번호로 알아보는 정규식 그룹 예제 */
SELECT REGEXP_REPLACE('010.1234.5678', '(\d{3})\.(\d{4})\.(\d{4})', '\1-\2-\3') FROM DUAL;

위 두 쿼리에는 별다른 차이가 없어보이지만 사실 큰 차이가 있다.


그룹으로 묶여있는 정규표현식은 \1, \2, \3... 순으로 INDEX 를 지정해 결과를 표시할 수 있다고 했는데 

이 INDEX 는 정규식에 사용한 그룹의 갯수만큼 자동으로 생성된다.


띄어쓰기로 알아보는 정규식 그룹 예제의 경우에는 ([가-힣]+) 만을 사용하고 있으므로 이 예제의 경우에는 \1 만이 사용 가능하고 

전화번호로 알아보는 정규식 그룹 예제는 (\d{3})\.(\d{4})\.(\d{4}) 의 총 3개 그룹으로 이루어져 있으므로 \3 까지 사용이 가능하다.


그렇지만 \1 만 사용이 가능하다고는 해도 배열(?) 같은 존재라 결과를 찍어보면 

띄어쓰기로. 알아보는. 정규식. 그룹. 예제입니다. 

라고 해당 정규식에 해당하는 모든 문자들이 제대로 치환이 되어 나올 것이다.


전화번호의 경우에는 기존에는 각각의 번호 사이에 점이 찍혀 있었는데 해당 쿼리를 돌려보면 010-1234-5678 로 

치환 되어 나올텐데 그 이유는 010.1234.5678 이 통째로 선택되도록 정규식을 선언했기 때문이다. 


만약 점까지 그룹화를 하게 된다면 아래처럼 사용할 수 있다. 끝!

/* 전화번호로 알아보는 정규식 그룹 예제 */
SELECT REGEXP_REPLACE('010.1234.5678', '(\d{3})(\.)(\d{4})(\.)(\d{4})', '\1-\3-\5') FROM DUAL;


댓글