[NLP] 토큰화 - 정규표현식

해피해피슈크림·2025년 5월 22일

💡 정규 표현식이란? 특정한 패턴을 가진 문자열을 추출하기 위해 사용되는 기법이다.

  • 정규 표현식은 특정한 패턴을 가진 문자열을 검색, 추출, 또는 수정하기 위해 사용되는 기법이다.
  • 파이썬 뿐만 아니라 문자열을 다루는 모든 곳에서 사용된다.

🌟 정규 표현식 구성 요소: 패턴 = 메타문자 + 리터럴

  • 패턴
    - 찾으려는 문자열의 규칙을 정의한 표현식을 패턴이라고 한다.
    • 정규 표현식의 패턴은 메타문자와 리터럴로 구성된다.
  • 메타문자
    - 패턴에서 특정 규칙이나 조건을 기술하기 위해 사용되는 특별한 의미를 가지는 문자
    • 예) a*: a를 0회 이상 반복을 뜻한다. a, aa, aaaa
  • 리터럴
    - 문자나 문자열을 패턴 내에서 그 자체로 사용하는 것을 말한다.
    • 예) aa 그 자체를 의미한다.

예시) 전화번호: 000 - 0000 - 0000 => 000, 0000: 메타문자, '-': 리터럴


✏️ 정규 표현식 메타 문자

문자 클래스: [ ]

  • [ ] 사이의 문자들과 매칭
  • -를 이용해 범위 지정
  • [^ 패턴]: ^로 시작하는 경우 '오면 안 되는 패턴'을 의미한다.

미리 정의된 문자 클래스: \w

  • \w: 문자와 숫자, _와 매치. 특수문자를 제외한 일반 문자를 말한다.
  • \s: 공백 문자와 매치.

글자 수와 관련된 메타문자: +, {m, n}

  • +: 앞에 문자(패턴)과 일치하는 문자가 1개 이상인 경우.
    - 예) r'\d+': 숫자 한 개 이상
  • {m}: 앞의 문자(패턴)가 m개.
    - 예) r'\d{2}'
  • {m,}: 앞의 문자(패턴)가 m개 이상.
    - 쉼표(,) 뒤에 공백이 들어오지 않도록 한다. a{3, } (X)
  • {m,n}: 앞의 문자(패턴)이 m개 이상 n개 이하.

문장의 시작과 끝 표현: ^, $

  • ^: 문자열의 시작. ^abc
    - 문자 클래스([ ])의 ^와는 의미가 다르다.
  • $: 문자열의 끝. abc$

기타: ., ( )

  • . 한 개의 모든 문자 (\n 줄바꿈 제외) (\.은 문자 그래도 점(.)을 의미)
  • ( ): 패턴 내 하위그룹을 만들 때 사용

😎 파이썬에서 정규 표현식 사용하기

✅ 모듈: re

  • 표준 모듈 re를 사용한다.

🤖 코딩 방식: 객체지향형과 함수형

객체지향형

  • 패턴 객체를 생성 후 메소드를 호출해 원하는 처리를 한다.
    p = re.compile(r'\d+')
    p.search('abc123def')

함수형

  • re 모듈의 원하는 작업을 하는 함수를 호출한다. Argument로 패턴과 처리할 값을 전달한다.
   re.search(r'\d+', 'abc123def')

🔍 검색 함수: 패턴과 일치하는 문장이 "있는지"

match(): 패턴으로 "시작하는 지"

  • match(대상문자열 [,pos=0])
  • 대상 문자열의 시작이 정규식과 일치하는 지를 조회한다.
  • pos: 시작 index 지정
  • 반환값
    - 일치하는 문자열이 있다면 -> Match 객체
    • 일치하는 문자열이 없다면 -> None

search(): 패턴이 "있는지"

  • search(대상문자열 [, pos=0])
  • 대상 문자열 전체 안에서 정규식과 일치하는 것이 있는지 조회한다.
  • pos: 시작 index 지정
  • 반환값
    - 일치하는 문자열이 있다면 -> Match 객체 (Search 아님)
    • 일치하는 문자열이 없는 경우 -> None

🔍 검색 함수: 패턴과 일치하는 문장을 "가져올 때"

findall(): 매칭되는 문자열들을 "리스트"로 반환

  • findall(대상문자열)
  • 대상문자열에서 정규식과 매칭되는 문자열들을 리스트로 반환
  • 반환값
    - 리스트(List): 일치하는 문자열들을 가진 리스트를 반환
    • 일치하는 패턴이 없을 경우 빈 리스트를 반환한다.

finditer(): 매칭되는 결과들을 조회할 수 있는 "Iterator"를 반환

  • finditer(대상문자열)
  • 대상문자열에서 정규식과 매칭되는 결과들을 조회할 수 있는 Iterator를 반환한다.
  • 반환값
    - callable_iterator
    • 일치하는 패턴이 없어도 iterator 객체는 반환되는데 next()StopIteration Exception이 발생한다.

✏️ 문자열 변경

sub(): 변경된 문자열 반환

  • sub(바꿀문자열, 대상문자열[, count=양수])
  • 대상문자열에서 패턴과 일치하는 것을 바꿀문자열로 변경한다.
  • count: 변경할 개수를 지정. (기본: 매칭되는 문자열은 다 변경)
  • 반환값: 변경된 문자열
import re
txt = "             월요일          좋아         ~~~           "
# txt.strip() # 좌우 공백 제거
# txt.replace("    ", "") # 개수가 일치해야 한다.
result = re.sub(r" +", " ", txt.strip()) # 공백들을 한 개 공백으로 변경 (패턴, 바꿀 문자열, 대상)
result
# 출력 결과: '월요일 좋아 ~~~'

월요일 좋아

subn(): 변경된 문자열과 변경 개수를 튜플로 반환

  • sub()와 동일한 역할
  • 반환값: (변경된 문자열, 변경된 문자열 개수)를 튜플로 반환
p = re.compile(r" +")
result = p.subn(" ", txt.strip())
print(type(result), len(result))
result

# 출력 결과
# type(result): <class 'tuple'> 
# len(result): 2
# result: ('월요일 좋아 ~~~', 2)

🛒 Grouping: 패턴 내 "하위 패턴" 만들기

  • 하위 패턴을 소괄호로 묶어준다.
  • 패턴의 일부를 하나의 그룹으로 묶는 기능으로, 매칭된 패턴의 일부를 재사용하거나, 특정 패턴이 일치하는지 확인할 때 유용하다.
    하츄핑

그룹핑.. 을 볼때마다 항상 티니핑이 생각난다.


🍩 Greedy와 Non-Greedy(Lazy) Matching

Greedy matching

  • 주어진 패턴에 만족하는 문자열을 최대한 넓게(길게) 잡아 찾는다.
  • 매칭시 기본 방식

Non-Greedy(Lazy) matching

  • 주어진 패턴에 만족하는 문자열을 최초의 일치하는 위치까지 찾는다.
  • 개수를 나타내는 메타문자(수량자)에 ?를 붙인다.
    • *?
    • +?
    • {m,n}?
txt = """
<ul>
    <li>python</li>
    <li>java</li>
</ul>
"""

# txt(html)에서 태그들을 조회
# "<ul>, <li>, </li>, <li>, </li>, </ul>"

p1 = r"<.+>" # <a>, <ul>, <section class='c1'>
p2 = r"<.+?>" # .+ 뒤 패턴의 문자를 처음 만나면 수량사 처리를 끝내라라
result1 = re.findall(p1, txt)
print(result1)
# ['<ul>', '<li>python</li>', '<li>java</li>', '</ul>']
result2 = re.findall(p2, txt)
print(result2)
# ['<ul>', '<li>', '</li>', '<li>', '</li>', '</ul>']
  • 결과 비교: <li>python</li>
    • Greedy: <li>python</li> 끝까지!
    • Non-Greedy: '<li>', '</li>'

0개의 댓글