파이썬에서 정규표현식 쓰기
1. 컴파일
1
2
import re
p = re.compile('\w+')
파이썬에서는 re라는 모듈을 import하여 정규표현식을 쓸 수 있다. 정규표현식을 쓸 땐 가장 먼저 사용할 정규표현식을 re 모듈의 compile() 함수에 대입하며 컴파일한 객체를 변수에 저장해 두어야 한다. 파이썬의 정규표현식에 관한 함수들은 원칙적으로 이 객체의 메서드를 호출하는 형태로 수행된다.
* 컴파일 옵션
- 컴파일 함수의 두 번째 인자로 컴파일 옵션을 지정하여 컴파일을 수행할 수 있다. 컴파일 옵션은 re 모듈의 변수의 형태로 돼있으며 각각 다음과 같다.
| 설명 | |
|---|---|
| re.VERBOSE, re.X | compile() 함수의 인자로 넣은 정규표현식에 주석을 써도 무시된다. |
| re.MULTILINE, re.M | 메타문자 ^, $를 문자열 전체의 맨앞, 맨뒤가 아니라 문자열 내 각 줄의 맨앞, 맨뒤에서 해당 문자열을 찾을 수 있게 한다. |
| re.IGNORECASE, re.I | 대소문자를 구분하지 않는다. |
| re.DOTALL, re.S | 메타문자 .이 개행문자를 포함하게 한다. |
2. 문자열 검색
1) match()
- 컴파일된 정규표현식이 match() 메서드의 인자로 전달된 문자열 전체와 일치하는지 여부를 검사하여, 일치한다면 그에 해당하는 match 객체를, 일치하지 않는다면 None을 리턴한다.
- 컴파일된 정규표현식의 메서드로서가 아니라 re 모듈의 함수 match()를 호출하는 방법도 있다. 이 경우 첫 번째 인자로 정규표현식을, 두 번째 인자로 비교할 문자열을 대입한다.
2) search()
- 컴파일된 정규표현식과 일치하는 문자열이 search() 메서드의 인자로 전달된 문자열 내에 포함되는지 여부를 검사하여, 일치하는 문자열이 있다면 그에 해당하는 match 객체를, 일치하는 문자열이 없다면 None을 리턴한다.
- search() 역시도 컴파일된 정규표현식의 메서드로서가 아니라 re 모듈의 함수를 호출하는 방법이 있다. 이 경우에도 첫 번째 인자로 정규표현식을, 두 번째 인자로 비교할 문자열을 대입한다.
3) findall()
- findall() 메서드의 인자로 전달된 문자열 내에서, 컴파일된 정규표현식과 일치하는 문자열을 모두 찾아 리스트로 만들어 그 리스트를 리턴한다.
- 다음은 findall() 메서드를 이용하여 주어진 문장을 단어 단위로 split해 리스트에 담아 리턴하는 코드이다.
1
2
p = re.compile('\w+')
words = p.findall("Yesterday, all my trouble seemed so far away...")
- 컴파일된 정규표현식에 그룹이 있을 경우, findall() 메서드가 리턴하는 리스트에는 그룹에 해당되는 문자들만이 튜플에 담겨 리턴된다. 예를 들어 정규표현식이 ‘\d([A-Z])’라면, ‘1A’ 같은 문자는 이 정규포함식에 포함은 되나 findall() 메서드에 인자로 전달될 경우 findall() 메서드에 의해 1이 삭제되어 A만이 리스트에 담겨 리턴된다.
- findall() 또한 컴파일된 정규표현식의 메서드로서가 아니라 re 모듈의 함수를 호출하는 방법이 있다. 이 경우에도 첫 번째 인자로 정규표현식을, 두 번째 인자로 비교할 문자열을 대입한다.
4) finditer()
- findall()과 거의 같은 기능을 하나, 리턴하는 문자열들을 ‘callable iterator’ 라는 형태의 객체에 담아 리턴한다. 이때 이 객체의 각 원소는 match 객체로 리턴된다.
- finditer()도 컴파일된 정규표현식의 메서드로서가 아니라 re 모듈의 함수를 호출하는 방법이 있다. 이 경우에도 첫 번째 인자로 정규표현식을, 두 번째 인자로 비교할 문자열을 대입한다.
* match 객체
- match 객체는 단순히 문자열이 아니라 메서드의 인자로 전달된 문자열에서 정규표현식에 부합하는 문자열의 위치에 관한 정보를 포함하는 객체이다. 다음 메서드를 호출하여 사용할 수 있다.
| 설명 | |
|---|---|
| .group() | 그 객체의 문자열을 리턴한다. 인자로 1 이상의 숫자를 넣으면, 그 숫자와 일치하는 그룹에 해당하는 문자열을 리턴한다. |
| .start() | 정규표현식에 부합하는 문자열이 메서드의 인자로 전달된 문자열의 몇번 인덱스에서부터 일치하기 시작하는지를 리턴한다. |
| .end() | 정규표현식에 부합하는 문자열이 메서드의 인자로 전달된 문자열과 일치하는 부분이 몇번 인덱스에서 끝나는지를 리턴한다. |
| .span() | 정규표현식에 부합하는 문자열이 메서드의 인자로 전달된 문자열의 몇번 인덱스에서부터 몇번 인덱스까지 일치하는지를 튜플에 담아 리턴한다. (.start(), .end()) 의 형식으로 담겨 있다. |
3. 문자열 치환
1) sub()
- 컴파일된 정규표현식과 어떤 문자열이 있을 때, 그 문자열에서 컴파일된 정규표현식과 일치하는 단어들을 새로운 단어로 교체할 수 있다. sub() 메서드를 사용하며, 교체할 새로울 단어를 첫 번째 인자로 받고 교체해야 할 문자열이 담겨있는 문자열을 두 번째 인자로 받는다. 다음은 sub() 메서드를 사용한 사례이다.
1
2
p = re.compile('[0-9]')
print(p.sub('*', 'There are 5 apples and 3 pears.'))
다음은 위 코드의 출력값이다.
There are * apples and * pears.
- sub() 메서드의 첫 번째 인자는 함수를 넣을 수도 있다. 이 경우 그 함수가 리턴하는 값으로 문자열 치환이 일어난다.
- 첫 번째 인자의 경우, \g<> 표현을 사용하면 정규표현식에서 지정한 그룹을 호출해 쓸 수 있다. 꺽쇠 안에 호출할 그룹의 인덱스 번호를 적어 쓴다. 다음은 \g<> 표현을 사용하여 주어진 주민번호 뒷자리를 *으로 치환하는 코드이다.
1
2
p = re.compile('(\d{6})-(\d)\d{6}')
print(p.sub('\g<1>-\g<2>******', '991231-1234567'))
- sub() 또한 컴파일된 정규표현식의 메서드로서가 아니라 re 모듈의 함수를 호출하는 방법이 있다. 이 경우 첫 번째 인자로 정규표현식을, 두 번째 인자로 치환할 새 문자열을, 세 번째 인자로 치환될 문자들이 담겨있는 문자열을 대입한다. 다음은 주어진 문자열의 소문자들을 대문자로 치환하는 코드의 한 예이다.
1
str1 = re.sub('([a-z])', lambda x: x.group(1).upper(), str1)
2) subn()
- subn() 메서드는 sub() 메서드와 동일한 작업을 수행하나, 결과를 튜플로 리턴한다. 이때 튜플의 첫째 원소는 sub() 메서드의 리턴값과 동일한 문자열이며, 둘째 원소는 치환이 일어난 횟수다.
* 파이썬의 정규표현식과 \
- 예를 들어 ‘\sky’라는 문자열을 컴파일하려는 경우, 이대로 써서 컴파일하면 ‘\s’ 부분이 whitespace 문자로 취급되어 의도와 다른 결과를 낳게 된다. 이 경우 원칙대로라면 \를 두번 써서 ‘\\sky’라고만 쓰면 문제가 해결돼야 하나, 파이썬 특유의 정규식 처리 방침으로 인해 ‘\sky’를 입력받은 것으로 처리된다. 결국 이를 해결하려면 ‘\\\\sky’와 같이 \를 무려 4개나 넣어주어야 비로소 의도한 것과 같은 결과를 얻을 수 있다.
- 단, compile() 함수에 인자로 넣을 때 따옴표 앞에 r을 붙여주면 \를 두 개만 써도 된다. 코드로 써 보면 다음과 같다.
1
p = re.compile(r'\\sky')