전체 페이지뷰

2016년 12월 2일 금요일

Regular expression with Python, Modifyng a string


Modifyng a string

지금부터는 정규식 내부에서의 문자열 
변환에 대해 알아보겠습니다.






split(string, maxsplit=0)

거의 대부분의 언어에서 split 메소드가 쓰이지만 re 모듈에서 이것이 더 강력한 이유는 정규표현식이 사용되기 때문입니다.  예를 들어 봅시다.

>>> re.split(r"\n", "Beautiful⇢is ⇢better⇢than⇢ugly.\nExplicit⇢is⇢better⇢than⇢implicit.")
['Beautiful⇢is⇢better⇢than⇢ugly.', 'Explicit⇢is⇢better⇢than⇢implicit.']

match가 \n이므로 그것을 기준으로 해서 나누었음을 알 수 있습니다. 좀 더 복잡한 예들을 살펴봅시다.

>>> pattern = re.compile(r"\W")
>>> pattern.split("hello⇢world")
['hello', 'world']

패턴이 \W(영문자가 아닌 것)이므로 위의 예에서는 공백을 기준으로 나뉘었습니다.

maxsplit 인자는 나눌 수 있는 최대 개수를 지정하고 나머지는 통째로 하나의 결과로서 반환합니다.

>>> pattern = re.compile(r"\W")
>>> pattern.split("Beautiful is better than ugly", 2)
['Beautiful', 'is', 'better than ugly']

두 단어만 split되고 나머지는 하나로 묶어서 리스트의 요소로 반환했습니다.
매칭된 패턴까지 포함해서 split하려면 어떻게 하면 될까요?

>>> pattern = re.compile(r"(\W)")
>>> pattern.split("helloword")
['hello', ' ', 'word']

위와 같이 그룹을 사용하면 됩니다.

sub(repl, string, count=0)

이 메소드는 매칭되는 패턴을 지정한 리터럴로 변환해서 반환합니다.
역시 예를 살펴 보겠습니다.

>>> pattern = re.compile(r"[0-9]+")
>>> pattern.sub("-", "order0⇢order1⇢order13")
'order-⇢order-⇢order-'

한 개 이상의 숫자에 매칭되는 패턴입니다. 'order0⇢order1⇢order13'에서 0,1,13에 해당됩니다. 그것들을 지정한 "-"로 바꾸어서 반환했습니다.

>>> re.sub('00', '-', 'order00000')
'order--0'

이런 식으로 쉘 상에서 직접 객체를 생성하지 않고도 사용 가능합니다.
'order00000'에서 '00'을 찾아 '-'로 대체하라는 명령입니다.

repl 인자 자리에는 메소드가 올 수도 있습니다.
예를 들어 다음과 같이 두 종류의 상품 목록이 존재하는 레가시 시스템을 관리한다고 생각해  봅시다. 

-1234
A193,B123,C124

이 상품코드를 다음과 같이 바꾼다고 할 때,
A1234
B193,B123,B124

다음과 같이 함수를 정의해 봅시다.

>>> def normalize_orders(matchobj):
if matchobj.group(1) == '-': return "A"
else: return 'B'
MatchObject를 받아 변경하는 코드입니다.
그리고 패턴을 지정합니다.

>>> pattern = re.compile(r'([-|A-Z])')
'-' 혹은 영어대문자 중에 하나가 오는 경우를 그룹으로 패턴 매칭시켰습니다.
그리고 함수를 첫째 인자로 주고 바꿀 문자열을 주면...

>>> pattern.sub(normalize_orders, '-1234A193B123B124')
'A1234B193B123B124'

와 같이 변환 되었습니다.

위의 함수에서 인덱스 1의 group을 지정한 이유를 알기 위해, 잠시 group operation에 대해 살펴보고 가겠습니다. 

이제 HTML에 마크다운을 적용한다고 해봅시다.(간단하게 하기 위해 bold체 적용하는 것만 예로 듭니다). 마크다운 알고 싶으시면 여기를 참조하세요.

>>> text = "imagine⇢a⇢new⇢*world*,⇢a⇢magic⇢*world*"
>>> pattern = re.compile(r'\*(.*?)\*')
>>> pattern.sub(r"<b>\g<1><\\b>", text)
'imagine⇢a⇢new⇢<b>world<\\b>,⇢a⇢magic⇢<b>world<\\b>'

'*'로 둘러싸인 부분을 패턴으로 지정하고 그 내부를 그룹으로 지정해 'world'라는 부분을 캡쳐합니다( non-greedy 패턴을 사용하기 위해 ?를 사용했습니다). 그리고 world라는 그룹을 \g<숫자>로 지정한 것입니다.
이렇게 해서 world 앞 뒤에 *가 사라지고 볼드체로 표시하라는 마크다운 기호로 둘러 싸여졌습니다.

count 옵션을 줘서 개수를 제한할 수도 있습니다.

subn(repl, string, count=0)

기본적으로 sub 메소드와 동일합니다. 차이점이라면 치환된 결과와, 치환한 횟수를 묶어 튜플로 반환한다는 것입니다.
위와 같은 예제를 들어 확인해보고 이번 단원을 마치겠습니다.

>>> text = "imagine⇢a⇢new⇢*world*,⇢a⇢magic⇢*world*"
>>> pattern = re.compile(r'\*(.*?)\*')
>>> pattern.subn(r"<b>\g<1><\\b>", text)
('imagine⇢a⇢new⇢<b>world<\\b>,⇢a⇢magic⇢<b>world<\\b>', 2)

댓글 없음:

댓글 쓰기