Py) TM - 정규표현식-04(대괄호)

Py) TM - 정규표현식-04(대괄호)

Pandas 객체 기반 정규표현식을 활용할 때 사용하는 메타문자 중 대괄호에 대해 알아본다.


개요

대괄호([])는 정규표현식(Regex)에서 문자 클래스(character class)를 정의하는 데 사용되는 주요 메타문자 중 하나이다. 일반적으로 연속된 여러 문자열 범위 패턴을 용이하게 지정하기 위해 주로 사용되나 엄밀하게 보자면 반드시 연속된 표현만 사용할 수 있는 것은 아니다. 이와 관련하여 상세하게 알아보도록 하자.

이론

연속 범위 매칭

대괄호 내부에 값을 입력할 때 하이픈을 활용하여 범위를 지정할 수 있다. 예를 들어 [a-z]는 소문자 알파벳을 의미하며 [0-9]는 숫자를 의미한다. 하이픈 왼쪽은 시작 문자, 오른쪽은 끝 문자를 의미한다. 그래서 [b-d]b, c, d를 의미고 [3-5]3, 4, 5를 의미한다.

연속범위의 기준은 ASCII 코드표를 기준으로 한다. 그래서 [A-Z]는 대문자 알파벳을 의미하며 [a-z]는 소문자 알파벳을 의미한다. 그러나 한글의 경우는 유니코드(Unicode)를 기준으로 한다. 그래서 [가-힣]는 한글 완성형 문자 전체를 의미한다. 특히 한글의 경우 채팅 내용이나 SNS 댓글 등에는 “ㅋㅋㅋㅋ”같은 초성을 많이 쓰는데 이 초성을 처리하고자 한다면 [ㄱ-ㅎ]를 사용할 수 있겠다.

숫자, 영어, 한글만 처리가능한 것이 아니라 다른 언어도 처리가 가능하며 해당 언어를 일괄로 처리하고자 할 때는 해당 언어의 첫 글자와 끝 글자만 알면 수월하게 할 수 있다. 예를 들어 일본어는 [ぁ-んァ-ヶ]로 처리할 수 있고 중국어는 [一-龥]로 처리할 수 있다.

불연속 범위 매칭

단순히 연속된 문자열만을 처리하는 것이 아니라 불연속된 문자열도 처리할 수 있다. 예를 들어 [abc]a, b, c 중 하나를 의미한다. 대괄호를 사용하지 않는다면 a|b|c와 같다. 사실상 대괄호를 사용하지 않더라도 구현이 가능하기 때문에 경우에 따라 꼭 대괄호를 사용하지 않아도 된다.

다중 범위 매칭

대괄호 내부에는 여러 범위를 지정할 수 있다. 예를 들어 영문 알파벳 전체를 매칭하고자 할 때는 [a-zA-Z]를 사용할 수 있다. 가끔 다중 범위를 매칭하고자 할 때 [a-z,A-Z]와 같이 콤마(,)를 사용하는 경우가 있는데 이는 잘못된 표현이다. 콤마를 사용하게 되면 콤마 자체가 문자로 인식되어 [a-z,A-Z]는 소문자 알파벳과 대문자 알파벳, 콤마를 의미하게 된다. 따라서 [a-zA-Z]로 표현해야 한다. 그리고 범위는 3개 이상도 사용할 수 있으며 [a-zA-Z0-9]의 경우 영문 알파벳 전체와 숫자를 의미하고 [0-24-68-9]의 경우 0, 1, 2, 4, 5, 6, 8, 9를 의미한다.

불연속 + 다중 범위 매칭

연속범위와 불연속범위를 혼합해서 사용하는 경우 [a-z135]라는 표현을 사용할 수 있다. 이는 영문 소문자와 숫자 1,3, 5에 대응되는 패턴이다. 그런데 하이픈을 매칭하기 위해서는 어떻게 할까? 하이픈은 기본적으로 대괄호 내부에서는 연속범위에 대응되기 떄문에 하이픈을 가장 앞 또는 뒤에 배치한다. 즉, [a-z-]는 영문 소문자와 하이픈을 의미하며 [a-z-135]는 영문 소문자, 하이픈, 숫자 1, 3, 5를 의미한다. 그런데 하이픈을 매칭하기 위해 대괄호 내부에 하이픈을 사용하는 경우 실수가 나기 쉽고 가독성이 떨어지기 때문에 대괄호 내부에서 하이픈을 사용할 때는 대괄호 내부에서 가장 앞에 두거나 가장 뒤에 두는 것을 권장한다.

반전 범위 매칭

대괄호 내부에 첫 번째에 캐럿(^)을 사용하면 해당 범위를 제외한 나머지를 매칭할 수 있다. 예를 들어 [^a-z]는 영문 소문자를 제외한 나머지와 매칭된다. 이 때 캐럿은 대괄호 내부에서 가장 앞에 위치해야 하는데 만약 캐럿이 대괄호 내부에서 가장 앞에 위치하지 않으면 일반 문자로 인식된다. 즉, [^a-z]는 영문 소문자를 제외한 나머지를 의미하지만 [a^z]는 “a”, “^”, “z”와 매칭되기 때문에 주의해야 한다.

실습

다음과 같이 라이브러리와 데이터를 준비한다.

1
2
3
import pandas as pd

ser = pd.Series(["abc", "ABC", "-,", "0123456789"])

앞의 이론 부분을 참고하여 다음의 코드를 보고 이해해보도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
ser.str.replace(pat = "[a-z]", repl = "", regex = True) # 1
## 0
## 1 ABC
## 2 -,
## 3 0123456789
## dtype: object

ser.str.replace(pat = "[a-zA-Z]", repl = "", regex = True) # 2
## 0
## 1
## 2 -,
## 3 0123456789
## dtype: object

ser.str.replace(pat = "[a-z,A-Z]", repl = "", regex = True) # 3
## 0
## 1
## 2 -
## 3 0123456789
## dtype: object

ser.str.replace(pat = "[a-z135]", repl = "", regex = True) # 4
## 0
## 1 ABC
## 2 -,
## 3 0246789
## dtype: object

ser.str.replace(pat = "[a-z-135]", repl = "", regex = True) # 5
## 0
## 1 ABC
## 2 ,
## 3 0246789
## dtype: object

ser.str.replace(pat = "[a-z135-]", repl = "", regex = True) # 6
## 0
## 1 ABC
## 2 ,
## 3 0246789
## dtype: object

2번과 3번 코드의 경우 쉼표가 어느 경우에 제거가 되는지 확인하는 것이 중요하다. 그리고 5번과 6번 코드의 경우 하이픈이 제대로 처리가 되는지 확인해야 하며 되도록이면 5번 방식 보다는 6번 방식으로 코드를 작성하는 것을 권장한다.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×