파이썬 - 정규표현식 기초 학습

정규표현식이란?


  • 특정한 규칙을 가진 문자열의 집합을 표현하는데 사용하는 형식 언어
  • 프로그래밍 언어 혹은 텍스트 에디터 등에서 문자열의 검색과 치환을 위한 용도로 사용
  • 정규표현식에서 사용하는 기호를 메타 문자라고 한다.
  • 메타 문자(meta characters) : 원래 그 문자가 가진 뜻이 아닌 표현식 내부에서 특정한 의미를 갖는 문자
    • ex) . 6 $ * + ? { } [ ] \ | ( )

문자 클래스 [ ]


  • 문자 클래스로 만들어진 정규식은 “ [ ] 사이의 문자들과 매치 “ 라는 의미를 갖는다.
  • 예를 들어 [abc]는 “a, b, c 중 한개의 문자와 매치” 를 의미한다.
    • “apple” –> 정규식과 일치하는 문자 “a”가 있으므로 매치
    • “bottle” –> 정규식과 일치하는 문자 “b”가 있으므로 매치
    • “dog” –> 정규식과 일치하는 문자 없으므로 매치되지 않음
  • [ ] 안의 두 문자 사이에 하이픈(-)을 사용하면, 두 문자 사이의 범위(from-to) 를 의미한다.
    • 정규표현식 [a-c]은 [abc]와 동일하고, [0-5]는 [012345]와 동일
    • [a-zA-Z] : 알파벳(소문자/대문자) 모두
    • [0-9] : 숫자
  • [ ] 안에 ^ 메타 문자는, 반대(not)라는 의미를 갖는다.
    • ^[0-9] : 숫자가 아닌 문자만 매치
  • 자주 사용하는 문자 클래스
    • ^ : 문자열 시작
    • $ : 문자열 종료
    • \d : 숫자와 매치
    • \D : 숫자가 아닌 것과 매치, [^0-9]와 동일
    • \s : whitespace 문자와 매치, [ \t\n\r\f\v]와 동일(맨 앞 빈 칸은 공백문자를 의미)
    • \S : whitespace 문자가 아닌 것과 매치, [^ \t\n\r\f\v]와 동일
    • \w : 문자+숫자와 매치, [a-zA-Z0-9_]와 동일
    • \W : 문자+숫자가 아닌 것과 매치, [^a-zA-Z0-9_]와 동일

Dot(.)


  • 정규표현식의 Dot(.) 메타 문자는 줄바꿈 문자인 \n를 제외한 모든 문자와 매치(옵션으로 re.DOTALL 옵션을 주면, \n 문자와도 매치)
  • a.b 는 “a + 모든문자 + b”라는 의미
    • ex) “aab”, “a0b”, “aAb” –> “a”와 “b”사이에 모든 문자를 의미하는 . 과 일치하므로 매치
    • ex) “abc” –> “a”와 “b” 사이에 어떤 문자도 없으므로 매치되지 않음
  • 주의 : a[.]b 는 “a + Dot(.)문자 + b”라는 의미
    • “a.b” 문자열만 매치

반복(*)


  • 의 의미는 바로 앞에 있는 문자가 최소 0번 이상 무한대로 반복될 수 있다는 것
    • ex) ca*t –> “ct”, “cat”, “caaaat” 매치

반복(+)


  • +의 의미는 + 바로 앞에 있는 문자가 최소 1번 이상 무한대로 반복될 수 있다는 것
    • ex) ca+t –> “cat”, “caaaat” 매치

반복({m,n},?)


  • {m,n}의 의미는 반복 횟수가 m부터 n까지인 것을 매치한다는 의미
    • m 또는 n 생략 가능
      • {3,} –> 반복 횟수 3번 이상인 경우
      • {,3} –> 반복 횟수 3번 이하인 경우
      • {3} –> 반복 횟수 3번인 경우
    • {1,} 는 * 메타 문자와 동일
    • {0,} 는 + 메타 문자와 동일
    • {0, 1} 는 ? 메타 문자와 동일
      • ab?c –> “a + b(있어도 되고 없어도 된다) + c”

파이썬에서 정규 표현식을 지원하는 re 모듈


  • 파이썬은 정규 표현식을 지원하기 위해 re(regular expression의 약어) 모듈 제공
  • re 모듈은 파이썬 설치될 때 자동 설치되는 기본 라이브러리
    1
    2
    import re
    p = re.compile('ab*')

정규식 이용한 문자열 검색


  • 컴파일 된 패턴 객체는 4가지 메소드 제공
    • match() : 문자열 처음부터 정규식과 매치되는지 조사
    • search() : 문자열 전체 검색하여 정규식과 매치되는지 조사
    • findall() : 정규식과 매치되는 모든 문자열을 리스트로 리턴
    • finditer() : 정규식과 매치되는 모든 문자열을 iterator 객체로 리턴
  • match, search는 정규식과 매치 될 경우, match객체 리턴(매치되지 않을 경우 None 리턴)
  • match

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import re
    p = re.compile('[a-z]+')

    m = p.match("python")
    print(m) # <_sre.SRE_Match object at 0x01F3F9F8>

    m = p.match("3 python")
    print(m) # None
    # "3 python" 문자열의 처음 문자인 3이 정규식 [a-z]+ 에 부합되지 않으므로 None 리턴

    # 파이썬 정규식 프로그램은 보통 아래와 같은 흐름으로 작성
    m = p.match('string goes here')
    if m:
    print('Match found: ', m.group())
    else:
    print('No match')
  • search

    1
    2
    3
    4
    5
    m = p.search("python")
    print(m) # <_sre.SRE.Match object at 0x01F3FA68

    m = p.search("3 python")
    print(m) # <_sre.SRE.Match object at 0x01F3FA30>
  • findall

    1
    2
    result = p.findall("life is too short")
    print(result) # ['life', 'is', 'too', 'short']
  • finditer

    1
    2
    3
    4
    5
    6
    7
    8
    result = p.finditer("life is too short")
    print(result) # <callable_iterator object at 0x01F5E390>
    for r in result:
    print(r)
    # <_sre.SRE_Match object at 0x01F3F9F8>
    # <_sre.SRE_Match object at 0x01F3FAD8>
    # <_sre.SRE_Match object at 0x01F3FAA0>
    # <_sre.SRE_Match object at 0x01F3F9F8>
    • finditer는 findall과 동일하지만, 반복 가능한 객체(iterator object)를 리턴한다. (match 객체)

match 객체의 메서드


  • match 객체의 메서드

    1
    2
    3
    4
    5
    m = p.match("python")
    m.group() # 'python'
    m.start() # 0
    m.end() # 6
    m.span() # (0, 6)
    • group() : 매치된 문자열 리턴
    • start() : 매치된 문자열의 시작 위치 리턴
    • end() : 매치된 문자열의 끝 위치 리턴
    • span() : 매치된 문자열의 (시작, 끝)에 해당하는 튜플 리턴
  • re.compile 축약 방법

    1
    2
    3
    4
    5
    p = re.compile('[a-z]+')
    m = p.match("python")

    # 컴파일과 match 메서드 한번에 수행
    m = re.match('[a-z]+', "python")

컴파일 옵션

  • 정규식을 컴파일할 때 아래와 같은 옵션 사용
    • DOTALL(S) : 메타문자 . 이 줄바꿈 문자를 포함하여 모든 문자와 매치할 수 있도록 한다.
    • IGNORECASE(I) : 대소문자 상관없이 매치
    • MULTILINE(M) : 여러줄과 매치(^, $ 메타 문자 사용과 관계있는 옵션)
    • VERBOSE(X) : verbose 모드 사용(정규식을 보기 편하게 만들고, 주석 등 사용 가능)
  • DOTALL,S (re.DOTALL 혹은 re.S)

    1
    2
    3
    4
    5
    6
    7
    8
    import re
    p = re.compile('a.b')
    m = p.match('a\nb')
    print(m) # None

    p = re.compile('a.b', re.DOTALL)
    m = p.match('a\nb')
    print(m) # <_sre.SRE_Match object at 0x01FCF3D8>
  • IGNORECASE,I (re.IGNORECASE 혹은 re.I)

    1
    2
    3
    4
    p = re.compile('[a-z]', re.I)
    p.match('python') # <_sre.SRE_Match object at 0x01FCFA30>
    p.match('Python') # <_sre.SRE_Match object at 0x01FCFA68>
    p.match('PYTHON') # <_sre.SRE_Match object at 0x01FCF9F8>
  • MULTILINE,M (re.MULTILINE 혹은 re.M)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import re
    p = re.compile("^python\s\w+")
    # ^ 메타 문자에 의해 python 문자열이 사용된 첫 번째 라인만 매치

    data = """python one
    life is too short
    python two
    you need python
    python three"""

    print(p.findall(data)) # ['python one']

    # ^ 메타 문자를 문자열 전체가 아닌 각 라인의 처음으로 인식시키고 싶은 경우
    p = re.compile("^python\s\w+", re.MULTILINE)

    print(d.findall(data)) # ['python one', 'python two', 'python three']
  • VERBOSE,X (re.VERBOSE 또는 re.X)

    • 이해하기 어려운 정규식을 주석 또는 라인 단위로 구분하여 가독성있게 작성하고 싶을 때 사용
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')

      charref = re.compile(r"""
      &[#] # Start of a numeric entity reference)
      (
      0[0-7]+ # Octal form
      |[0-9]+ # Decimal form
      |x[0-9a-fA-F]+ # Hexadecimal form
      )
      ; # Trailing semicolon
      """, re.VERBOSE)

백슬래쉬 문제


  • “\section”이라는 문자열을 찾기 위한 정규식을 만들고 싶은 경우

    • \section에서 \s 문자가 whitespace로 해석되므로, \\section 으로 변경하여 사용하여 이스케이프 처리를 한다.

      1
      p = re.compile('\\section')
    • 하지만, 실제 파이썬 정규식 엔진에는 파이썬 문자열 리터럴 규칙에 의하여 \\\로 변경되어 \section이 전달된다.

    • 따라서, 파이썬은 \\\\ 백슬래쉬 4개를 사용해야 한다.

      1
      p = re.compile('\\\\section')
    • 상기와 같은 문제를 해결하기 위해 파이썬 정규식에는 Raw string이 생겨났다.

    • 즉, 컴파일해야 하는 정규식이 Raw String임을 알려줄 수 있도록 파이썬 문법이 만들어진 것

      1
      p = re.compile(r'\\section')
    • 정규식 문자열 앞에 r 문자를 선행하면 이 정규식은 Raw String 규칙에 의해 백슬래시 2개 대신 1개만 써도 두개를 쓴 것과 동일한 의미를 가진다.