Programming/SQL

패턴비교 연산자. 2021-06-28

최동훈1 2021. 6. 28. 15:58

우선 지난시간에 배웠던 정규식을 이용하지 않은  단순 패턴비교연산자(LIKE)의 용례를 복습겸 풀어보자.

SELECT * FROM NOTIECE WHERE NAME LIKE '최%';
--이러면 '최'로 시작하는 1개 이상의 모든 단어가 출력됨. 최, 최훈, 최미미, 최모리모리 등..
SELECT NAME AS '이름', ID, PHONE FROM MEMBER WHERE NAME LIKE '최__';
--이러면, '최'로 시작하는 세글자의 이름만 추출해서 출력됨.
SELECT NAME name, pwd FROM MEMBER WHERE NAME LIKE '%울산%';
--이러면, 이름에 울산이라는 단어가 앞이나 뒤, 중간에 포함되 있기만 하면 다 추출된다.

그런데  우리는 %와 _ 연산자를 통해 우리가 원하는 정보를 뽑아내기에는 많은 한개가 있다. 그래서 조금더 정확하고 구체적인 패턴으로 원하는 바를 출력할수 있는 정형식이 필요하다.

 

우선, 숫자를 패턴화할수 있는 대표적인 표현식들이다.

\d, {}, [] 

우리가 전화번호를 출력하고 한다고 가정하자.

기존의 방식으로는

SELECT * FROM NOTICE WHERE NUMBER LIKE '%-%-%';
-- 이러면 '안녕-안뇽-강녕' 아니면, 012135-5165-8724 이런 값들도 문자/숫자 관계없이 다 출력된다.

그러나 '숫자' 만을 출력하고 싶다면, LIKE 명령어 앞에 REGEXP_LIKE(필드명, 정규식)이런식으로 정규식을 사용한다는 표현을 쓰고, decimal 형만 검색한다는 \d 문자로 쓴다면, 숫자로된 형식을 지키면서 출력 가능하다.

정규식을 사용한다는 REGEXP_LIKE 명령어 사용법.

SELECT * FROM NOTICE WHERE REGEXP_LIKE(TITLE, '^\d\d\d-\d\d\d\d-\d\d\d\d&');
--이러면, 문자가아닌, 숫자만 출력된다. 예) 123-4567-6429;
--\d 가 붙여진 갯수가 뽑아내려는 문자열에서 정수로 이루어진 갯수
--그런데, \d를 너무 반복적으로 사용한다면, 불편하니 {}를 쓰면 된다.
SELECT * FROM NOTICE WHERE REGEXP_LIKE(TITLE, '^\d{3}-\d{3,4}-\d{4}&');
--{}속에 들어가있는 숫자는 숫자의 '갯수'이다. 그런데 {3,4} 이것은 3자리또는 4자리를 표현하는 것이다.

또한 정규식의 시작과 끝을 알리는 연산자는 각각 ^, $ 인데, 이것은 무조건 ^과 $ 사이에 존재하는 정규식 패턴만 일치하는 문자만 출력하라는 뜻이다. 예를들어 위 두번째 명령어 같은 경우에는 "최동훈의 번호 : 010-1556-6429 이다." 이런 문자열은 아예 match 되지 않는다. 왜냐하면, ^뒤에 나오는 정규식 패턴으로 시작하지 않았고, &바로전 까지의 정규식 패턴으로 끝나지 않았기 때문이다. 따라서, 만약 해당 정규식을 "포함"하는 문자열을 출력하고 싶다면, ^과 &연산자를 뺴면 된다.

 

그럼, 아예 전화번호 형식에 맞게 첫 글짜가 010, 011, 012...등으로  시작하는 숫자만 출력할수 없을까? 바로 [] 연산자를 이용하면 된다. [ ] 연산자는 '하나의 문자'만 대변하고, 그안에 들어가는 숫자들은 다 OR로 연결된다.  예를 들자면

SELECT * FROM NOTICE WHERE REGEXP_LIKE(TITLE,'01[0123456789]-\d{4}-\d{4}');

이렇게 쓴다면 첫글짜가 01이고 [ ] 괄호안에 들어간 수중 1개가 올수 있다는 뜻이다. 01 0~9까지 다 가능.그런데 이렇게 하나하나 다 쓰기 귀찮으니 범위를 표현하는것도 가능하다. ex) 01[012-9] -> 0, 1, 또는 2~9까지의 수 한개를 의미

 

요약

 

* 정규식의 자리수를 표현하는 대표적인 패턴은 [ ]과, { }이다.

 

* [ ]는 한 자리만을 대변한다. 즉, 이 [ ] 안에 들어있는 모든 수 각각 한 자리에 올 수 있는것으로 정의된다. 또한 - 기호를 통해 범위도 지정 가능하다.  

 

* { }는 여러자리를 올 수 있음을 정규식 기호 뒤에 붙임으로서 나타낼 수 있다. 그러나 [ ] 연산자와는 다른점이, '자리수' 만 정해주고, 구체적으로 어떤 후보군의 문자/숫자 가 올수 있는지는 정할수 없다.

 

* [0-9] 이렇게 범위자체가 자연수의 범위면 \d연산을 통해 Decimal digit(10진수 0부터 9까지 각각의 숫자) 범위에 해당 '한 글자'의 범위를 정할수 있다.

 

 

다음은 01로 시작하는 전화번호의 형식을 그대로 지키는 정규식을 표현법이다. 모두 같은 표현을 하고있다. 비교하면서, 정리해보자.

 

01[0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9];

01[0-9]-\d\d\d\d-\d\d\d\d;

01[0-9]-\d{4}-\d{4};

 

그렇다면 문자는 어떨까? 예를 들면 이메일을 출력하는데 조건이 이렇다.

'1개이상의 문자와 첫글자는 숫자로 시작하면 안됨' '@' '동일조건' 이런 조건을 앞서 배운 정규식으로만 표현한다면

[A-Z0-9a-z]

 이것밖에 모르겠다.. 즉, 이걸 여러번 써야 하나? 이런 생각이 든다. (A-Z까지 가능 또는 숫자 다가능 소문자 다가능) 그리고 정규식을 찾아보니 자릿수를 정할수 있는 연산자는 [ ] { }외에도 *, +, ? 등이 있는데 각각의 의미는

 

1. * : 0개이상의 문자/숫자.

2. + : 1개이상의 문자/숫자.

3. ? : 0개또는 1개의 문자/숫자. 

이다. 그럼

[A-Z0-9a-z]+

 이렇게 써야할까? 아니다. 너무 복잡하다. 그렇다면 0-9까지의 digit을 나타내는 \d 란 연산자가 있듯이, 문자+숫자 전부를 나타내는 연산자는 없을까? 

찾아보니 있다. 바로 \w이다.

\w+@\w+.(org|com|net)

이걸 적용시키면 대충 정규식이 완성되었다. 그런데, | 연산자는 또 뭘까? 바로 OR 기호이다. 

 

그런데 한가지 적용시키지 않은 조건이 있다. 바로 숫자가 첫 글자로 올 수 없다는 것이다.

\D\w*@\D\w*.(org|com|net)

\D는 [^0-9]이런 의미를 가지고 있다. ^는 NOT의 논리기호이다. 즉 \D는 숫자를 제외한 모든 문자 '한개'를 나타낸다.

 

공부시간 3시간.

순공부시간 1시간 30분.