정규표현식 - 개요!

정규표현식 개요

정규표현식(Regular Expression), 줄여서 regex라 부르는 일종의 도구.

수많은 언어에서 쓰이고 있으며 가장 적은 코딩으로 가장 큰 효율을 뽑아낼 수 있다고 생각된다.

  • Ben
  • .
  • www.fortal.com
  • [a-zA-Z0-9]*
  • \r\n\r\n

위의 이상한 문자열 모두 정규표현식의 일종
생소하지만 하나씩 알아보자.

마침표(.)

마침표는 어떤한 문자나 알파벳, 숫자, 심지어 문자 부호로 쓰인 특수기호 등과 일치함

마침표는 어디에서든지 쓰일수 있음, 여러개 쓰일수 있음

특수문자 마침표 찾기 (escape)

그럼 모든 문자가 아닌 정말 특수문자 마침표(.)를 찾으려면 어떻게 해야할까…

\. 앞에 백슬레시를 붙이면 된다, regex에서 문자를 찾기위해 특수문자가 여러개 사용되는데
정말 해당 특수문자만을 찾고싶으면 대부분 \ 백슬레시를 붙이면 됨.

메타문자로서의 역할에서 탈출(escape)해서 하나의 문자로 인식받게 하는 것을 escape라고 한다.

문자하나 찾기

정규표현식에 정말 문자를 쓰면 해당 문자를 문자열 사이에서 찾아낸다. 문자와 마침표를 쓰면 해당 문자와 마침표에 해당하는 문자를 찾아낸다. na.을 사용하면 naa~naz, na1~na9na뒤에 특수문자까지 찾아냄.

문자집합 찾기

만약 모든 문자를 찾지 않고 내가 원하는 문자집합안에서만 찾고 싶다면?
마침표가 아닌 [] 대괄호 안에 찾고싶은 문자집합을 넣어야한다.

[12]a.\.xls = 1또는 2로 시작하고 a가 붙고 아무문자하나와 .xls로 끝나는 문자열 찾기.

1~9로 시작하는 문자는 [123456789]로 표시해야하는데 너무 길니까 [1-9]로 표시할 수 있다.

숫자 외에도 아스키 문자에도 적용 가능,
[a-z], [A-Z], 단 [A-z]는 사용하면 안됨, 대문자와 소문자 사이에 ^, ], [ 등 다른 아스키 특수 기호들이 들어있음.

깔끔한 정규표현식을 위해 문자집합에서 범위를 지정하도록 하자.

RGB패턴은 #뒤에 6개의 A~F 범위의 영문자, 0~9사이의 숫자로 이루어 진다.
RGB패턴을 찾기위한 정규표현식은 다음과 같이 표현 할 수 있음.

#[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]

만약 해당 문자, 문자집합이 아닌 모든 문자를 찾고싶다면 ^를 사용한다.

[0-9]0~9까지를 찾고
[^0-9]0~9가 아닌 모든 문자를 찾는다.

메타문자

지금까지 써온 특수문자, ., ], [ 등의 특수문자들이 모두 메타문자이다.
이 메타문자를 하나의 문자로써 문자열사이제서 찾으려면 백슬레시를 사용해 escape해야 했다.
escape해주는 특수문자\ 또한 메타문자로써, 문자열 사이에서 \찾고싶으면 앞에 또 이스케이프문자인 백슬래쉬를 사용하면 된다 \\.

스페이스, 탭, 계행(CRLF) 등을 찾는 메타문자는 다음과 같다.

메타문자 설명
\r CR(Carriage Return, 커서를 앞으로)
\n LF(Line Feed, 계행)
\t tab

윈도우 환경에선 \r\n으로 계행을 표현하고 리눅스, 유닉스 환경에서 \n으로 쓰인다.

이런식으로 알파벳 앞에 이스케이프 문자\를 붙여 메타문자로 쓰는경우가 많다.

숫자, 숫자가 아닌문자를 가리키는 메타문자

숫자를 찾고싶으면 [0-9]를 쓰면 된다.

숫자가 아닌 무자를 찾고싶으면?
[^0-9] 를 쓰면 된다.

하지만 숫자,영문자를 찾는 정규표현식은 너무 자주 쓰여 따로 전용 메타문자가 있다.

dD 앞에 \를 붙이면 숫자와 숫자가 아니 문자를 찾을 수 있다.

\d: 숫자하나와 같다([0-9])
\D: 숫자가 아닌 문자하나와 같다([^0-9])

영숫자, 영숫자가 아닌문자를 가리키는 메타문자

wW 앞에 \를 붙인다.

wW는 알파벳, 숫자 뿐 아니라 _밑줄까지 검색한다.

\w: 밑줄을 포함한 모든 알파벳과 숫자 [a-zA-Z0-9_]
\W: 밑줄을 포함한 모든 알파벳과 숫자가 아닌문자[^a-zA-Z0-9_]

위에서 했던 RGB 문자 찾는 패턴도 간략하게 할 수 있다.
#[w][w][w][w][w][w]
비록 _ 또한 포함하겠지만….

모든 공백문자, 공백문자가 아닌 문자 찾기

\s: 모든 공백문자, [\f\n\r\t\v]
\S: 모든 공백문자가 아닌것, [^\f\n\r\t\v]

여기서 \f는 페이지 넘김, \v는 수직탭을 뜻함(자주 쓰이지 않음)

이제 공백문자 찾는다고 힘들게 \r부터 \t까지 나열하지 않아도 된다.

반복문자 찾기

지금까지 한 문자에 대해서만 찾았는데 이메일이 처럼 문자열의 길이가 고정되지 않을경우 반복되는 문자사이에서 패턴을 찾아야 한다.

a@b.c라는 문자를 찾기위해선 \w@\w\.\w 패턴을 사용하면 되지만
abcd@gmial.com, abcde@daum.com 등 문자열이 가변길이라면 위와같은 패턴을 수백, 수천개 만들어야함.

문자 하나이상을 찾으려면 + 플러스 기호를 사용하면 된다.
\w+@\w+\.\w+

\w+\w가 하나이상 반복되는 문자열을 찾는다. +는 문자집합에서도 사용될 수 있다.
[\w.]+\w혹은 문자. 이 하나이상 반복되는 문자열을 찾는다.

[ ]안에서 문자. 을 찾을때 escape문자를 생략해도 된다,
물론 써도 문제가 생기지는 않는다.

+, *, ? 수량자

셋다 반복되는 문자를 찾기위한 메타문자이다.

+은 위에서 보았듯이 페턴에 일지하는 문자가 하나이상 오는지 체크

*는 패턴에 일치하는 문자가 0번, 혹은 한번이상 반복할 경우.

사실 위의 \w+@\w+\.\w+는 정확한 이메일을 찾는 정규표현식이 아니다.
.abcd@gmail.com 같은 문자열도 찾아내는데 이메일 맨앞에는 .과같은 특수문자가 오면 안된다.(중간에는 와도 된다)

따라서 맨앞에는 영숫자가 하나 이상 들어오고
그 뒤에 영숫자가 오거나 말아야 한다.
^\w+[\w.]+@\w+\.\w+

?는 패턴에 일치하는 문자가 있거나 없거나(반복아님),

http:// 혹은 https:// 를 찾고싶을 때 사용한다.
http뒤에 s가 오거나 없는 문자열만 찾고싶을때 다음 정규식을 사용한다.
s가 반복하지 않아야 하기때문에 *은 사용할 수 없다.
https?://[\w./]

주의: 반복문자 찾는 메타링크는 [ ]밖에 위치하도록 하자.

반복구간 찾기 {}

+혹은 * 수량자를 사용하면 반복하는 문자를 찾을 수 있지만 몇번 반복하는지 까지 찾고 싶다면 반복구간을 찾는 {} 메타문자를 사용해야한다.

위에서 찾았던 RGB패턴 또한 반복구간을 사용하면 간단하게 정규식을 짤 수 있다.

#[0-9a-zA-F][0-9a-zA-F][0-9a-zA-F][0-9a-zA-F][0-9a-zA-F][0-9a-zA-F] 에서
#[0-9a-zA-F]{6}로 바꿀 수 있다.

[0-9a-zA-F]가 6번 정확히 반복되는 문자를 찾는다.

정확히 6번 반복되는 반복구간을 지정할 수 도 있지만 4~6번 반복되는 구간을 지정할 수 있다.

날짜양식은 여러가지가 있다.

2019-04-07, 2019-4-7, 19-04-07 등 년도의 경우 2번 ~ 4번 숫자가 반복될 수 있고 월, 일의 경우 숫자가 1번 ~ 2번 반복될 수 있다.
정확한 반복구간이 정해져있지 않을때 ,를 사용해서 반복 범위 구간을 지정할 수 있다.

\d{2,4}-\d{1,2}-\d{1,2}

물론 9999-99-99 같은 말도안되는 날짜도 일치한다.(나중에 조건을 집어넣자)

?는 반복구간 {0,1}과 같은 역할을 한다.
n번 이상 반복하는 구간을 찾고 싶다면 {n, } 을 사용.

탐욕적 수량자, 게이른 수량자

*+같은 메타문자는 탐욕적(greedy)으로 문자를 찾도록 설계되었기 때문에 예상과 달리 넓은 범위 부터 일치하는 문자열을 찾아낸다.

<b>My</b> name is <b>Hong gil dong</b> 

이런 문자열에서 <b></b> 를 포함한 문자를 찾기위해 <[bB]>.*</[bB]> 정규식을 사용한다면 찾는 범위는 다음과 같다.
<b>My</b> name is <b>Hong gil dong</b> 전체를 찾아옴. <b>....</b>

탐욕적으로 가장 큰 범위로 인식하기 때문에 이를 방지하기 위해 게으른(lazy) 수량자로 바꿔줄 필요가 있다.

<[bB]>.*?</[bB]> 수량자 뒤에 ?를 붙이면 된다.
<b>My</b><b>Hong gil dong</b> 가장 작은 범위를 찾아낸다.

위치찾기 (Positioning Matching)

찾고싶은 문자열이 어디에 위치하는지 정확히 정할 필요가 있다.

The cat scattered his food all over the room
위 문자에서 cat이라는 정규식을 통해 cat문자열을 찾는 경우 'The'뒤에있는 'cat'뿐 아니라 s'cat'tered 또한 찾아온다.

이를 방지하기 위해 경계를 지정하여 위치를 확실하게 할 필요가 있다.

단어 경계

\b키워드를 사용하면 단어 경계를 지정가능하다.
위에 사용했던 정규식을 \bcat\b로 변경, 'cat'이라는 단어를 찾아낸다.

여기서 \b 메타문자는 단어의 경계를 지정하는 공백, 탭, 컴마, 대시(긴막대기), 계행 등을 탐지하는 역할은 한다.

중요한건 단여 양 끝에 추가해주어야 하는것, 한쪽에만 추가한다면 \bcat, cat\b 해당 정규식으로 시작하거나 끝나는 위치를 찾는다.

\B키워드는 \b의 반대이다.
경계문자로 둘러싸이지 않은 정규식에 일치하는 문자열을 찾아낸다. 경계문자로 둘러싸인 문자열을 무시한다.

문자열 경계

단어의 경계는 단어 시작, 단어 마지막 주변에 경계를 뜻하는 문자를 기준으로 위치를 구분한다.

반면 문자열의 경우 전체 문자열의 시작과 마지막을 찾는 정규식을 ^캐럿과 $를 사용해서 경계를 지정하고 위치를 구분한다.

올바른 xml문서의 경우 문서 시작부분이 <?xml .... ?> 태그로 시작한다.

ex: <?xml version="1.0" encoding="UTF-8" ?>

올바른 xml문서임을 판단하기 위해 문서 시작부분에 위의 태그가 쓰여있는지 정규식으로 판단해보자.

일단 xml문서의 모든 문자열을 읽어와서 첫 줄에 xml태그가 있는지 검사해야 한다.

지금까지 봐온 정규식으로 <\?xml.*\?> 이런식으로 지정할 수 있다.

단 이 정규식으로 문저의 시작에 위 정규식에 해당하는 태그가 있는지, 문서 중간부분에 있는지 판단할 수 없다.

문자열 시작부터 정규식에 해당하는 문자열이 오는지 확인하려면 ^캐럿을 사용한다.
^<\?xml.*\?>

위의 정규식은 문자열 시작에 무조건 <?xml이 있어야 일치한다.

^[] 안에쓰면 부정을 뜻하는 메타기호로 쓰인다.
패턴 시작부분에 써야 위의 문자열 시작의 의미를 갖는다.

xml시작이 무조건 <?xml 로 시작하면 좋겠지만 공백, 탭, 계행이 있을 수 있음으로 \s메타태그를 사용해야 한다.
^\s*<\?xml.*\?>

그리고 탐욕적 탐색을 방지하기 위해 수량자를 게으른 수량자로 변경해주자. ^\s*<\?xml.*?\?>

문서가 xml태그로 시작하는지 체크하는게 생각보다 간단하지 않다….

다중행 모드

정규표현식에선 문자열 구분을 계행으로 하지 않는다. 여러줄로 이루어진 문서 통째로 하나의 문자열로 인식한다.

만약 계행이후 시작을 특정 태그로 시작하는걸 찾는다던지, 계행이전 끝을 특정 문자열로 끝나다는지 를 체크하려면 다중행 모드를 사용해야 검사할 수 있다.

계행을 문자열 구분자로 인식하도록 해야하는데 이때 사용하는게 m(multi line) 메타문자이다.
정규표현식 엔진에 따라 사용법이 다르지만 다중행 모드와 함께 ^, $를 사용하면 계행 이루에 시작, 계행 이후 끝을 나타내도록 할 수 있음.

.js같은 파일에서 모든 주석에 해당하는 문자열을 찾고싶을 때 다음 정규식을 사용한다.
(?m)^\s*//.*$

하위 표현식

html사이에 공백이 들어가 레이아웃이 틀어진다면 자바스크립트를 사용해 다음 pattern을 사용해 보자

var pattern = />\s*</ig;
var replacement = "></";

d_content = d_content.reaplce(pattern, replacement);
console.log(d_content);
Flag Meaning Description
i Ignore Case 대소문자를 구별하지 않고 검색한다.
g Global 문자열 내의 모든 패턴을 검색한다.
m Multi Line 문자열의 행이 바뀌더라도 검색을 계속한다.

카테고리:

업데이트: