Python에서 정규표현식 모듈인 re 모듈을 사용하다가 한가지 문제가 있었습니다. 이거 때문에 몇 시간을 삽질 했는지 모르겠어요... 문제 상황은 다음과 같았습니다. 아래와 같은 문자열이 있었다고 가정해 볼까요?
>>> info = "nero (Ulsan, Korea), shiba (Tokyo, Japan), mickey (LA, USA)"
저는 이 문자열을
["nero (Ulsan, Korea)", "shiba (Tokyo, Japan)", "mickey (LA, USA)"]
이런 식으로 리스트를 반환받고 싶었는데, split()
으로도 해결이 안되고 parse
라는 모듈을 다운 받아 해봤는데도 잘 안돼서 결국 잘 안쓰는 정규표현식으로 처리를 해야겠구나 생각을 했어요. 그래서 아래와 같이 포맷을 짰습니다.
>>> import re
>>> p = re.compile(r'.* \(.*, .*\)')
간단히 포맷을 설명을 하면,
.
: 모든 문자를 매치.
*
: 앞에 있는 문자가 0개 이상일 경우.
\(
, \)
: 괄호를 문자 그대로 나타낼 경우 사용.
이렇게 해서 나오는 결과는 의도치 않게 아래와 같이 나옵니다.
>>> p.findall(info)
['nero (Ulsan, Korea), shiba (Tokyo, Japan), mickey (LA, USA)']
한참 이유를 생각을 했었습니다. 물론, python이 매치를 틀리게 한 것은 아닙니다! 근데 아무리 생각해도!! 문자열을 끝까지 다 탐색하지 않아도 중간에 끊을 수도 있는 것인데 왜 괄호 마저도 .
에 포함시키며 다 읽어나가야 하는지 이해를 못하겠더군요. 충분히 매치할 수 있는 문자열이 앞쪽에 있는데도 말이지요. 그래서 전방 탐색이며, 후방 탐색이며 몰랐던 정규 표현식 문법도 써보며 이유를 찾아보려고 했지만 잘 되지 않았습니다...
그러던 중, 한 블로그의 포스트를 찾게 되었는데요. 정규표현식 탐색의 Greedy, Lazy 방식에 대한 개념에 대해 설명하고 있었습니다. 기본적으로 정규표현식은 Greedy 한 방식으로 탐색을 한다고 합니다. 그러니, 제가 짜놓은 정규표현식으로 탐색을 할 때 최대한 많이 문자열을 매치시키려 python은 노력을 했던 것입니다. 제가 원했던 방식은 Greedy 한 방식이 아니라, Lazy한 방식(혹은 non-greedy한 방식이라고도 하는군요.)이었다고 하네요. 그렇게 하려면 메타 문자 뒤에 ?
를 붙이면 된다고 합니다! 그래서 저는 정규표현식을 아래와 같이 변경하고 다시 해봤습니다.
>>> p = re.compile(r'.*? \(.*?, .*?\)')
>>> p.findall(info)
['nero (Ulsan, Korea)', ', shiba (Tokyo, Japan)', ', mickey (LA, USA)']
제가 원하는대로 잘 되었네요. 두번째, 세번째 인덱스의 쉼표와 공백은 제거해주면 되니까요. 이렇게 저의 2시간짜리 삽질을 마무리 하게 되었습니다 :(
모두 즐거운 개발 되세요!
'Python' 카테고리의 다른 글
Python에서 반복문으로 변수 선언하기. (0) | 2019.03.26 |
---|