정규식이란? Regular Expression? regex?
내용
- 정규식, 정규 표현식 이란 무엇일까요? : 정의와 개념을 이해합니다.
- 패턴 정의 문법 : 정규식을 사용하기 위해 필요한 문법을 배웁니다.
- 정규식 활용 방법 예시 (in Python 파이썬에서) : 실제 사용하는 예시를 배웁니다.
- 정규식의 활용 : 어디에 쓰는지 알아봅니다.
- 배운 내용 확인(연습문제)
정규식, 정규 표현식 이란 무엇일까요?
바로~~~
정규식은 특별한 문자열의 집합(패턴)을 표현하는 언어 입니다.
정규식은 패턴을 표현하기 위한 규칙을 정의 하는 방법으로 (특별한 의미로 인식되는) 메타문자와 (일반 문자) 정규문자를 이용해서 정의 할 수 있습니다.
개념
조금 더 확실하게 알아보겠습니다. 사실 개념은 간단합니다. 텍스트(문장, 문단 또는 문서)가 주어 졌을때 특정한 패턴을 찾으려면 찾고자 하는 동일한 문자를 모두 한번에 하나씩 입력하고 조회해서 찾아 볼 수 있습니다. 그러나 조건이 조금 복잡해지면 이렇게 하는 것은 불편하고 복잡할 때가 있습니다. 이럴때 특정한 표현 규칙이나 기호를 활용하여 다양한 규칙을 간단하게 정의할 수 있습니다. 이렇게 정의된 것이 바로 정규식입니다. 표현 규칙은 특별한 문자가 무엇을 의미하는지 정하고, 반복 횟수 표현은 어떻게 할 것인지 등을 정한 것입니다. 즉, 문법이지요. 아래에서 예를 들어보겠습니다.
다음과 같은 텍스트가 있습니다.
target = "나는 정규식을 잘 알고 잘 사용할 수 있습니다. 정규식은 재미있고 유용합니다. 정규식으로 쉽게 코딩 할 수 있습니다."
이것을 대상 텍스트, 즉, target 이라고 하겠습니다. target에서 '정규식'이라는 문자와 아무 문자 하나가 추가된 모든 단어를 찾고 싶습니다. 예를 들면 "정규식이", "정규식은", "정규식도" 등이 되겠네요. 이렇게 해서도 패턴을 정의할 수 있습니다.
이처럼 찾고자하는 것이 패턴인데, 예를들어 정의해보면
' 정규식가 ', ' 정규식기 ', ' 정규식구 ', ' 정규식에 ', ... 등이 가능합니다. (찾기 원하는 내용의 앞/뒤에 공백하나 ' '를 추가했습니다.)
'정규식' 뒤에 무슨 문자가 올지 모르기 때문에 모든 가능한 문자를 적어줘야 합니다. 정확히 일치하는 패턴을 정의하다보니 너무 많아서 무한대는 아니지만 너무 많은 것 같네요. 이렇게 생성 가능한 많은 문자 패턴들을 미리 만들어 놓고 하나하나 비교해가면서 target에 패턴이 있는지 없는지를 확인할 수 있습니다. 그런데 방금 보신것 처럼 '정규식'이라는 단어 뒤에 모든 하나의 문자를 허용하는 패턴을 정의하기 위해서 너무 많은 내용을 일일히 나열해야합니다. 정말 비효율적이고 힘든 일이 지요. 그래서 정규식이 필요합니다. 위에서 찾고자하는 엄청난 길이의 패턴을 정규식으로 표현하면 다음과 같이 매우 간단합니다.
"[\s]+정규식[\w]+[\s]+"
정말 간단해서 보기 좋지 않으신가요? 이해는 안되더라도 동일한 의미라면 정규식으로 표현된 내용이 훨씬 간단하다는 것을 알수 있습니다. '\s' 는 공백 한칸을 나타내는 특별한 문자(메타문자)이고요. '+'는 앞에 정의한 원자(정규문자나 메타문자)가 몇번 출현/반복하는지를 정하는 수량자(quantifier) 중에 하나입니다. 이것이 의미하는 것은 수량자 바로 앞 한 문자(이번 예에서는 \s 또는 \w)가 1회 이상 발생하는 것을 의미합니다. 조금 더 상세한 정의 방법은 뒤에 자세히 설명하겠습니다.
한번 더 예를 들어 보겠습니다. 이번에는 target2가 아래와 같은 텍스트라고 가정하겠습니다.
target2 = '이번 정규식은 쉽다. 정규식1번이 2번보다 좋은가? 정규식이라고 해서 모두 같은게 아닙니다. 이정규식 해석 방법은? 정규식9번을 해석하시오"
자, 이제 '정규식' 뒤에 숫자1부터 9중에 하나가 들어가고 앞에 하나 이상의 공백이 있는 패턴을 찾고 싶다고 생각해보겠습니다. 찾고 싶은 패턴들을 그냥 모두 나열해보면 다음과 같습니다.
패턴 = " 정규식1", " 정규식2", " 정규식3", " 정규식4", " 정규식5", " 정규식6", " 정규식7", " 정규식8", " 정규식9"
이것을 정규식으로 표현해보면
"[\s]+정규식\d"
입니다. 정말 간단하게 표현되는 것을 확인할 수 있습니다. 여기서 '\d'는 숫자 한자리를 의미합니다.
위의 예시가 정확하게 이해되지 않으시더라도 적어도 한가지는 이해하셨을 것 같습니다. 즉, 복잡하고 다양한 패턴을 정의하는데 정규식을 쓰면 쉽게 할 수 있다는 것을 아셨을 것 같습니다. 정규식 문법을 하나씩 배워나가면 이해가 쉬워 지실껍니다. 자 그럼 어떻게 정규식 패턴을 정의할 수 있는지 자세한 문법을 알아보겠습니다.
패턴 정의 문법
정규식은 어째건 간에 텍스트 즉, 문자열(문장 또는 문서)에서 찾고자 하는 문자나 패턴을 정의하는 것입니다. 그래서 결론적으로 정규식도 문자나 문자열입니다. 그래서 쌍따옴표("") 사이에 찾고자하는 문자나 패턴을 정의합니다. 정규식은 정규문자와 메타문자로 구성됩니다. 정규문자는 일반적으로 쓰는 문자를 말합니다. 영어의 알파벳이나 한글의 자음/모음, 또는 숫자 같은 것이 되겠습니다. 메타문자는 특별한 의미를 부여한 문자를 말합니다.
메타 문자(Meta Character)
메타 문자는 특수한 의미를 지니는 문자를 말합니다. 즉, '이 문자는 이런 의미이다'라고 미리 정한 것이지요. 다시 말하면, 정규식을 사용할 때의 문법이라고 할 수 있습니다. 그래서 잘 알아두어야 정규식을 정확하게 쓸수 있습니다. 자, 그럼 정규식에는 어떤 메타문자와 문법이 있는지 알아보겠습니다.
메타 문자 | 기능 | 설명/의미 | 예시 | 예시설명 |
[ ] | 문자 클래스 (집합) |
가능한 문자들의 집합을 의미합니다. []안에 있는 한글자 한글자가 찾고자하는 한글자가 될 수 있는 것 입니다. []안에는 결국 문자 하나의 가능한 조건/집합을 정의하게 됩니다. | "[a-m]" | a부터 m중에 하나의 문자 |
\ | 백슬래쉬 | 바로 뒤에 오는 한 문자와 합쳐서 특수기호로 사용됩니다. | "\d" | 숫자를 나타내는 특수 문자로 숫자 1자리의 모든 수를 의미합니다. |
. | 문자 | 새줄 문자(개행문자, \n)를 제외한 모든 하나의 문자. | "he..o" | he 다음에 새줄 문자(\n)를 제외한 어떤 문자든 2개가 있고 그뒤에 o가 있는 패턴을 의미합니다. |
^ | 처음 | ^ 다음의 내용으로 시작 | "^hello" | 시작이 hello인 패턴을 의미합니다. |
$ | 끝 | $ 전의 내용으로 끝 | "planet$" | planet 으로 끝나는 패턴을 의미 |
* | 0회 이상 반복 (수량자) |
* 직전의 정규문자/메타문자가 0회 이상 반복 | "he.*o" | .이 0회 이상 반복, 즉 heo, helo, hello, hellllo 모두 패턴 매칭됨 |
+ | 1회 이상 반복 (수량자) |
+ 직전의 정규문자/메타문자가 1회 이상 반복 | "he.+o" | .이 1회 이상 반복, 즉 helo, hello, hellllo 들이 패턴 매칭됨 |
? | 0 또는 1회 (수량자) |
? 직전의 정규문자/메타문자가 0 또는 1회 반복 | "he.?o" | .이 0 또는 1회 발생, 즉 heo, helo 들이 패턴 매칭됨(hello는 안됨) |
{n, m} | 지정횟수 반복 (수량자) |
{} 직전의 문자가 n회 이상 m회 이하 반복 | "he.{2}o" | .이 2회 발생, 즉 hello 만 패턴 매칭됨(heo, helo, helllo는 안됨) |
¦ | 선택 | ¦ 전에 문자 또는 후에 문자 | "true¦false" | "true" 또는 "false"의 패턴을 의미 |
() | 그룹 | 그룹으로 묶기, 여러 식을 하나로 묶을 수 있음 | "a(b¦d)c" | "abc¦adc"와 같은 의미 |
수량자와 선택, 그룹을 제외한 메타 문자는 결국 하나의 문자 조건을 나타냅니다.
모든 수량자는 {n, m} 방식으로 바꾸어서 정의할 수도 있습니다.(비추합니다. 왜냐하면 *, +, ?를 사용하는 것이 더 직관적이기 때문입니다.)
특수 기호(Special Character)
하나의 특수 기호를 이용해서 문자, 숫자, 또는 공백을 각각 대신할 수 있습니다. 그리고 문자열의 시작이나 끝, 그리고 단어의 시작이나 끝 등 출현 위치에 대한 규칙을 정할 수 있습니다. (처음 정규식을 접하시는 분은 굵은 글씨로 된 \d, \s, \w만 아셔도 충분합니다.)
특수 기호 | 의미 | 예시 |
\A | 명시된 문자로 문장이 시작하는 경우 일치하는 것을 반환 | "\AThe" |
\b | 명시된 문자가 단어의 시작이나 끝에 위치하는 경우 일치하는 것을 반환 (문자열 시작전에 "r"을 추가함으로써 내용이 "raw string"으로 받아 들여지게 합니다.) |
r"\bain" r"ain\b" |
\B | 명시된 문자가 단어의 끝이나 시작이 아닌 위치에서 발견되는 경우에 반환 | r"\Bain" r"ain\B" |
\d | 숫자와 매칭되는 문자(숫자)를 반환합니다. (0부터 9까지의 숫자) | "\d" |
\D | 숫자가 아닌 문자 찾기 | "\D" |
\s | 공백 문자와 일치되는 문자 찾기 | "\s" |
\S | 공백 문자가 아닌 문자 찾기 | "\S" |
\w | 모든 문자에 포함되는 문자 찾기(문자는 a 부터 Z까지,한글의 경우 '가'부터 '힣'까지, 숫자는 0부터 9까지, 그리고 underscore _ 기호도 매칭됨) | "\w" |
\W | 문자에 포함되지 않는 문자 찾기(\w가 아닌 문자) | "\W" |
\Z | 문자열의 끝에 정의한 문자가 있는지 문자 찾기 | "Spain\Z" |
집합(Sets)
문자 클래스 안에 들어가는 내용을 Sets이라고 합니다. 각 예시와 설명을 살펴 보시지요.
Set 예시 | 설명 |
[arn] | a, r, 또는 n과 매칭되는 문자를 찾습니다. |
[a-n] | a 부터 n 사이의 모든 소문자 알파벳과 매칭되는 문자를 찾습니다. |
[^arn] | a, r, 또는 n이 아닌 모든 문자와 매칭되는 문자를 찾습니다. |
[0123] | 0, 1, 2, 또는 3 인 숫자와 매칭되는 숫자를 찾습니다. |
[0-9] | 0부터 9까지의 모든 숫자와 매칭되는 숫자를 찾습니다. |
[0-5][0-9] | 0부터 5사이의 모든 숫자로 시작하는 첫번째 자리숫자와 0부터 9사이의 모든 숫자로 시작하는 두번째 자리 숫자를 (2자리 숫자와) 매칭되는 숫자를 찾습니다. 즉, 00 부터 59 사이의 숫자를 찾습니다. |
[a-zA-Z] | a부터 z까지의 모든 소문자 알파벳 또는 A부터 Z까지의 모든 알파벳과 매칭되는 문자를 찾습니다. 즉, 모든 알파벳을 찾습니다. |
[+] | 문자 클래스 [] 안에 있는 특수문자는 모두 그냥 그대로 매칭하는 것을 찾습니다. 즉, +, *, ., |, (), $,{} 이러한 기호가 문자클래스 []안에서 사용되면 같은 모양의 기호가 target 문자열에 있는지 없는지를 찾습니다. |
마지막에 설명한 것처럼 Sets를 정의할 때 사용되는 특수 기호 들은 앞에서 설명한 매타 문자의 정의와 다른 의미 입니다. 그냥 특수문자 그대로를 패턴으로 찾습니다. 따라서 혼동되지 않게 주의 하셔야 합니다. 특히 세번째에 설명한 '^'의 경우 문자 클래스 안에서는 부정의 의미를 갖지만 밖에서는 문자의 시작을 나타냅니다.
정규식 활용 방법 예시 (in Python 파이썬에서)
첫번째 예시를 프로그래밍 언어인 파이썬을 이용해서 코딩해본 내용입니다.
1번라인은 python에서 정규식 사용을 쉽게 해주는 re 모듈을 임포트해서 가져옵니다. 3번라인에서 대상이 되는 텍스트를 설정합니다. 5번에서는 re모듈에 compile 함수를 이용해서 정규식을 정의합니다. 7번라인에서는 정의한 정규식을 이용해서 대상 텍스트에서 정규식에 해당하는 패턴을 찾아서 matches라는 변수에 전달해 줍니다. 9번부터 10번라인에서는 매칭된 내용을 출력하는 명령어 내용입니다.
상기 내용을 test.py로 저장하고 실행하면 아래와 같은 결과가 나옵니다.
$ python testtest.py
<_sre.SRE_Match object; span=(2, 8), match=' 정규식을 '>
<_sre.SRE_Match object; span=(26, 32), match=' 정규식은 '>
<_sre.SRE_Match object; span=(43, 50), match=' 정규식으로 '>
$
두번째 예시를 코딩해본 내용입니다.
상기 내용을 test2.py로 저장하고 실행하면 아래와 같은 결과가 나옵니다.
$ python test2.py
<_sre.SRE_Match object; span=(11, 16), match=' 정규식1'>
<_sre.SRE_Match object; span=(64, 69), match=' 정규식9'>
$
보신 것처럼 파이썬의 re 모듈을 이용하여 쉽게 정규식을 사용할 수 있습니다. re는 Regular Expression의 약자이며 파이썬 라이브러리의 이름 입니다. re 모듈에서는 이 밖에도 여러가지 함수를 제공합니다.
finditer 함수
위의 예시에서는 매칭되는 내용을 오브젝트로 받을 수 있는 finditer 함수를 이용했습니다. 이렇게 얻은 오브젝트는 여러 정보가 있습니다. 출력한 내용을 보면 매칭되는 오브젝트임을 표시하고(sre.SRE_Match object), span 에서 매칭되는 범위를 표시해 주며(span=(11, 16)), 매칭되는 내용을 보여 줍니다(match=' 정규식1'). 여러개가 매칭되면 여러개의 객체가 반환 됩니다.
findall 함수
findall 함수는 패턴이 매칭된 내용을 리스트로 만들어서 반환 합니다. 예를 들어 두번째 예시를 findall 함수로 변경시 반환 값은 리스트(['정규식1', '정규식9'])가 되서 출력되는 내용이 아래와 같이 됩니다.
$ python test2.py
정규식1
정규식9
$
sub 함수
sub 함수는 매칭된 내용을 다른 내용으로 대체가 필요할 때 사용하는 함수 입니다. 두 번째 예에서 발견된 내용(정규식1, 정규식9)을 '정규식100'으로 바꾸도록 코드를 수정하고 실행해보겠습니다.
$ python test2.py
이번 정규식은 쉽다.정규식100번이 2번보다 좋은가? 정규식이라고 해서 모두 같은게 아닙니다. 이정규식 해석 방법은?정규식100번을 해석하시오
정규식의 제일 앞에 공백(\s)이 있어서 공백을 포함한 내용(' 정규식1')이 sub 에서 정의한 "정규식100"으로 대체 된 것을 보실 수 있습니다.
search 함수
search 함수는 텍스트 내에 정규식에 해당하는 패턴이 존재하는 경우 첫번째 내용을 오브젝트로 반환 합니다. 그래서 여러가 매칭되더라도 제일 첫번째 내용만 반환합니다. 매칭되는 것이 없을 경우 None을 반환합니다.
$ python test2.py
<_sre.SRE_Match object; span=(11, 16), match=' 정규식1'>
$
정규식의 활용
정규식은 어디에 쓸까요? 결국 정규식이 문자열의 패턴을 정의하기 때문에 이러한 정의가 필요한 경우를 생각해면 됩니다. 일반적으로 접하게되는 활용은, Text 내용 중에 특정한 패턴이 있는지를 찾아내는 Text검색에 사용될 수 있습니다. 이메일, 워드 문서, ppt문서, PDF문서 등 많은 문서 형태에서 검색이 필요합니다. 이러한 검색을 위한 패턴 정의 및 실행에 사용할 수 있습니다. 그리고 각종 컴퓨터 프로그램에서도 텍스트 내용에 대한 유효성 체크 또는 검색과 변경 등의 작업을 위해 많이 사용됩니다. 이처럼 활용할 경우가 많으니 개발자인 경우 정확히 알아두면 많은 도움이 될 것입니다. 이처럼 활용처가 많기 때문에 많은 프로그래밍 언어에서 쉽게 코딩 할 수 있도록 정규식 라이브러리를 제공합니다. 파이썬에서는 위에서 보신 re 모듈이 되겠습니다.
배운 내용 확인(연습문제)
배운 내용 확인을 위해 정규식을 하나 만들어 보시지요. 웹 페이지에서 휴대폰 전화번호를 입력받는 기능이 있다고 가정하시죠. 이때 입력받은 내용이 휴대폰 전화번호에 맞는 내용인지 아닌지를 검증하기 위해 정규식을 만들어 보시지요. 즉, 정규식을 만드는 이유는 사용자가 이상한 값이나 문자를 입력하지 않았는지 확인하기 위해서 입니다. 그래서 우리가 만든 정규식을 가지고 일치하는 패턴을 찾게되면 사용자가 정확하게 입력했다고 할 수 있습니다. 휴대폰 전화번호의 구조는 다들 아시겠지만 다음과 같습니다. 숫자 3자리로 시작하고, 그 다음 대시('-')가 나오고, 그다음 숫자 3자리 또는 4자리가 나오고, 그다음 대시('-')가 나오고, 마지막으로 숫자 4자리가 나오는 패턴 입니다. 이 조건을 정규식 문법으로 옮겨보겠습니다.
숫자 3자리로 시작하고, --> \d\d\d 또는 \d{3}
그 다음 대시('-')가 나오고, --> '-'
그 다음 숫자 3자리 또는 4자리가 나오고, --> ([\d]{3}|[\d]{4}]) 또는 \d{3,4}
그 다음 대시('-')가 나오고, --> '-'
마지막으로 숫자 4자리가 --> \d\d\d\d 또는 \d{4}
모두를 합쳐보면 아래와 같습니다.
"^\d{3}-\d{3,4}-\d{4}$"
요약
이상으로 정규식에 대해서 알아보았습니다. 정규식에 대한 정의와 개념, 문법에 대해서 알아보았으며, 파이썬 언어에서 실제로 구현하는 방법에 대해서 알아보았습니다. 정규식의 활용 내용에 대해서도 알아보았고 마지막으로 연습문제까지 풀어보았습니다.
질문 댓글은 언제나 환영이며 구독, 좋아요를 눌러 주시면 다음 글을 더 편하게 보실 수 있습니다.
감사합니다.
w3c schools의 내용을 참고했습니다.