티스토리 뷰

발생일: 2017.08.18

키워드: re, 정규식, lookbehind, 그룹, group, regular expression, regex, split

문제:
문자열을 정규식으로 split 할 때, 정규식 구문에 그룹이 포함되어 있었더니 원하는 결과가 나오지 않는다.

왜 그런 걸까?


해결책:

split()으로 전달하는 패턴에 그룹이 있으면, 분할한 결과 뒤에 그룹 매칭값이 붙는다.
아래 예제를 보면 쉽게 이해할 수 있다.

    re.split('-', 'aaa-bbb')
    -> ['aaa', 'bbb']

    re.split('(-)', 'aaa-bbb')  # 그룹으로 묶음
    -> ['aaa', '-', 'bbb']  # split 결과에 그룹이 포함된다

    re.split('(-)', 'aaa-bbb-ccc')  # 여러 번 잘라질 때도 동일
    -> ['aaa', '-', 'bbb', '-', 'ccc']

    re.split('(-)(x)', 'aaa-xbbb-xccc')  # 그룹이 여러 개인 경우
    -> ['aaa', '-', 'x', 'bbb', '-', 'x', 'ccc']


그룹에 포함되지 않게 하려면 ?: 를 넣어주면 된다.

    re.split('(?:-)', 'aaa-bbb')



논의:

# 자바스크립트에서도 동일

자바스크립트에서도 동일하다.

    'aaa-bbb'.split(/-/); //-> ['aaa', 'bbb']
    'aaa-bbb'.split(/(-)/); //-> ['aaa', '-', 'bbb']

그룹이 포함된 정규식 구문으로 split 하는 경우에 원하는 결과가 나오지 않는다.


# 글을 문장 단위로 자르기

사실 이 문제는 글을 문장 단위로 자르는 코드를 작성하면서 발생했다.

예를 들어,

    "오늘 아마존의 주가는 4.2% 증가했다. 구글은 3.4% 증가했다."

와 같은 문장을 첫 문장과 두 번째 문장으로 구분하려고 했다.

아래와 같이 단순히 마침표로만 자를 수도 있는데,

    re.split('\.', text)

이렇게 하면, 자르는 기준에 4.2%, 3.4%와 같은 소수점도 포함되기 때문에 lookbehind 옵션으로 마치표 앞의 문자는 숫자가 아닌 것만으로 제한했다.

    re.split('(?<=[^0-9])\.', text)


이때까지 잘 동작했는데, 개행 문자를 정규식 구문에 추가하기 위해 그룹으로 묶었다.

    re.split('((?<=[^0-9])\.|\n)', text)


이랬더니, 결과에 마침표가 포함된 거였다.

아래처럼 그룹에 포함되지 않게 변경하는 것으로 수정했다.

    re.split('(?:(?<=[^0-9])\.|\n)', text)


그치만 정리하다 보니, 그룹 없이 그냥 캐릭터를 쓰는 게 훨씬 간결하겠네...

    re.split('(?<=[^0-9])[\.|\n]', text)
반응형
댓글
공지사항