re 정규표현식, 정규식(regular expression, regex, pattern ) : 미완성

Hyun·2022년 6월 27일
0

기타등등

목록 보기
8/11

요약

re.sub(r’[^0-9a-z-_.], ‘’, new_id)

re.sub([.]+,., new_id)		

new_id = re.sub(r'[^0-9a-z-_.]', '', new_id)

정규표현식 ( regular expression, pattern )

  • 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하며 주로 복잡한 문자열을 처리할 때 사용한다.

  • 정규표현식의 각 문자는 메타문자, 정규문자로 이해됨

    • 정규 문자 : ex. 가, a 등 문자 그대로 매칭되는 문자
    • 메타 문자 : 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용되는 문자 ( 아래에서 자세히 다룬다. )
  • a. 은 'a', 'ax', 'a0'과 일치할 수 있다.

  • .은 포괄적, [a-z]는 덜 포괄적, a는 정확한 패턴(a만 일치)

  • seriali[sz]e == ["serialise", "serialize"]

  • 와일드카드? : 파일 목록에서 비슷한 이름을 글로브 처리

  • r의 역할은? : raw string으로 변환해준다.(\을 정규문자화)

    print("\가4개인데? \\\\ ")	# \가4개인데? \\ 
    print(r"\가4개인데? \\\\ ")	# \가4개인데? \\\\
    print("\'는? \'\'\'\' ")	# '는? '''' 
    print(r"\'는? \'\'\'\' ")	# \'는? \'\'\'\'

method

  • re.match(pattern, string, flags(option)) : 문자열이 처음부터 정규식과 매치되는지 조사
    • group() : 매치된 문자열을 return
    • start(), end() : 매치된 문자열의 시작 위치, 끝 위치를 각각 return
    • span() : 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 return
    matchObj = re.match('a', 'a')
    print(matchObj)					# <_sre.SRE_Match object; span=(0, 1), match='a'>
    m = re.match("a", "aba")		# <... span=(0, 1), match='a'>
    m = re.match("a", "bba")		# None
  • re.fullmatch(pattern, string, flags(option)) : 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 return한다.
    m = re.fullmatch("a", "aba")		# None
    m = re.fullmatch("a", "aaa")		# None
    m = re.fullmatch("a", "a")		# <... span=(0, 1), match='a'>
  • re.search(pattern, string, flags(option)) : 문자열 앞에서부터 검색하여 정규식과 매치되는 것이 있는지 조사
    searchObj = re.search('a', 'a')
    print(searchObj)					# <... span=(0, 1), match='a'>
    m = re.search("a", "aba")		# <... span=(0, 1), match='a'>
    m = re.search("a", "bba")		# <... span=(2, 3), match='a'>
  • re.findall(pattern, string, flags(option)) : 정규식과 매치되는 모든 문자열(substring)을 list 형태로 return한다.. 겹치는 문자는 overlapping 되지 않는다.
    m = re.findall("a", "aba")			# ['a', 'a']
    m = re.findall("a", "bbaaa")		# ['a', 'a', 'a']
    m = re.findall("aa", "bbaaa")		# ['aa']		NO OVERLAPPING
  • re.finditer(pattern, string, flags(option)) : 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 return한다.
    for matchObj in re.finditer('a', 'baa'):
        print(matchObj)
    # <_sre.SRE_Match object; span=(1, 2), match='a'>
    # <_sre.SRE_Match object; span=(2, 3), match='a'>
  • 예시
# compile을 통해 모듈 생성 ( 다음에 해당하는 부분 찾기 )
# 여러번 사용할 때 편하다.
phone = re.compile(r"""
010-    # 핸드폰 앞자리 
\d{4}-  # 중간자리
\d{4}  # 뒷자리
""", re.VERBOSE)

phone = re.compile(r"010-\d{4}-\d{4}") # 위와 같은 결과가 나온다.
m = re.match(r"010-\d{4}-\d{4}", "0000")
info = ['홍길동  :  010-1234-1234', '고길동 010-5678-5679']

for text in info:
  match_object = phone.search(text)		# string 중 phone 정규식에 해당하는 부분 찾아서 저장
  print(match_object.span())		# (8, 21) , (4, 17) : 주어진 string 중 해당 부분 (start_idx, fin_idx-1)
  print(match_object.group())		# 저장된 부분의 string 출력
  									# 010-1234-1234 , 010-5678-5679

컴파일 옵션

syntaxlong syntaxinline flagmeaning
re.Ire.IGNORECASE(?i)대소문자 구분 없이 일치
re.Mre.MULTILINE(?m)^와 $는 개행문자 위치에서 일치
re.Sre.DOTALL(?s)마침표는 개행문자와 일치
re.Are.ASCII(?a){\w, \W, \b, \B}는 ascii에만 일치
re.Ure.UNICODE(?u){\w, \W, \b, \B}는 Unicode에 일치
re.Lre.LOCALE(?L){\w, \W, \b, \B}는 locale dependent
re.Xre.VERBOSE(?x)정규표현식에 주석을 달 수 있음
  • DOTALL(re.DOTALL ?s or re.S) : .이 개행(줄바꿈, \n) 문자에 상관없이 모든 문자와 match하는 option (\n을 문자로 보지 않는다.)

    p = re.compile('a.b')
    m = p.match('a\nb')		# m : None
    p = re.compile('a.b', re.DOTALL)
    m = p.match('a\nb')		# <... span=(0, 3), match='a\nb'>
    re.findall('(?s)a..', 'abc a  a\na')		# ['abc', 'a  ', 'a\na']
    re.findall('(?is)a..', 'Abc')		# ['Abc']
  • IGNORECASE(re.IGNORECASE or re.I) - 대소문자에 관계없이 매치하는 option

    p = re.compile('[a-z]+', re.I)		# [a-z]+ 정규식은 소문자만 의미함
    p.match('Python')	# <...span=(0, 6), match='Python'>
  • MULTILINE(re.MULTILINE, re.M)

    • ^ 메타 문자 : ^str에서 str로 시작해야 한다.
    • $ 메타 문자 : str$에서 str로 끝나야 한다.
    import re
    p = re.compile("^python\s\w+")	# 해석 : python으로 시작하고 그 뒤에 공백문자, 그 뒤에 단어가 와야한다.
    m = re.compile("^python\s\w+", re.MULTILINE)	# 각 줄마다 정규식 적용
      
    data = """python one
      life is too short
      python two
      you need python
      python three"""
    
    print(p.findall(data))		# ['python one']
    print(m.findall(data))		# ['python one', 'python two', 'python three']
  • VERBOSE(re.VERBOSE, re.X)

    • 정규식을 여러줄에 걸쳐 작성할 수 있도록 하는 option, 주석 #도 사용 가능하다.
    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"에서, \s가 공백문자(whitespace)로 해석된다.
    • \가 문자열 그 자체임을 알려주기 위해서 \을 두번 써서 해결하거나 r을 통해서 raw string임을 알려주어 해결할 수 있다.
      p = re.compile('\section')		# => ' ection'
      p = re.compile('\\section')		# => '\section'
      p = re.compile('\\\\section')		# => '\\section'
      p = re.compile(r'\\section')		# => '\\section'
    • 알파벳이나 숫자를 escape(\)하면 에러가 나거나 다른 의미의 정규식 token이 될 수 있다.
    • \a, \e, \f, \n(개행 문자), \r, \t(가로 탭), \v(세로 탭)
      matchObj = re.findall('\t ', 'a\tb\tc\t \t d')		# ['\t ', '\t ']
      # 주어진 문자열에서 '가로탭 + 공백' 찾기
    • \w, \W, \d, \D, \s, \S, \b, \B는 문자 집합을 뜻한다.
      - 각각의 의미는 []의 별도 표기법에서 볼 수 있다.

문자 클래스

[ ] : 여러 문자 중 하나와 일치 ( OR )

  • [abc] 와 'a'는 match된다! 'a', 'b' or 'c'
  • 내 메타 문자 역할 : \ ^ - ]
    • '-' : 범위(from - to) 혹은 차집합
      • 범위 : [가-힣] (한글 한 글자에 일치), [a-zA-Z] (알파벳 모두 일치 (z-a 불가능!)), 0-9, [^0-9] (숫자가 아닌 문자만 일치 ( ^는 반대(not)라는 의미 ))
      • 차집합 : [a-z-[g-z]] == [a-f] == [abcdef]
        - 교집합 && : and와 같지만, 버전에 따라 지원하지 않을 수도 있다.
    • '^' : not, 여집합
    matchObj = re.fullmatch("You[;']re studying re module[.,]", 'You;re studying re module,')		# <... (0, 26), match='You;re studying re module,'>
  • 별도 표기법 : 대문자와 소문자는 서로 반대의 관계로 볼 수 있다. ( 한글자 )
    • \d == [0-9] : 숫자와 매치
    • \D == [^0-9] : 숫자가 아닌 것과 매치
    • \s == [ \t\n\r\f\v] : whitespace 문자와 매치
    • \S == [^ \t\n\r\f\v] : whitespace 문자가 아닌 것과 매치
    • \w == [a-zA-Z0-9_] : 문자 + 숫자 (alphanumeric)와 매치
    • \W == [^a-zA-Z0-9_] : 문자 + 숫자(alphanumeric)가 아닌 문자와 매치 ( 비단어 문자)
    • \b : 단어 문자 경계와 비단어 문자 사이와 매칭 ( \w에 일치되는 문자 + \W에 일치되는 문자 사이에서 일치됨 )
    • \B : \b의 반대 ( \w + \w or \W + \W 인 두 문자 사이에서 일치 )
    re.findall(r'\w\b\W\B', 'ab  c d  == = e= =f')	# ['b ', 'd ', 'e=']
    # "단어문자 + 비단어 문자 + 비단어 문자"인 것을 찾기!
    예시 1. \bline\b : line과만 일치 ( line : 단어 문자, 비단어 문자 + line + 비단어문자 )
    예시 2. \Bcat\B : stacatto와 일치, cat, catch, copycat과 불일치 ( cat : 단어 문자, "단어 문자 + line + 단어문자"이여야 한다.)
    예시 3. re.findall(r'\b', 'a')		# ['', ''], 단어 문자 + 비단어 문자(\n?)
    예시 4. re.findall(r'\B', 'a')		# [],	단어 문자 + 단어 문자 혹은 그 반대가 없음.
    예시 5. re.findall(r'\b', 'a aa')		# ['', '', '', ''], 	'a', 'a ', ' a', 'a'사이의 경계
    예시 6. re.findall(r'\B', 'a aa')		# [''],		'aa'사이의 경계

. (dot) : 모든 문자와 일치 (.당 한 글자)

  • . 은 아무글자 1개
a.b		# a0b, aab, abb, a-b	-> 모두 True
		# ab, a					->False
  • [.] 는 .한개 그 자체를 뜻함
a[.]b		# a.b	-> True		문자 . 그대로를 의미 (모든문자 x)
		# a0b	-> False
import re

li = ["color", "colour", "coooolor", "excolor", "colr", "xcoloor", "colr", "cor", "colllllr", "colsr"]

for word in li :
  if re.search('col.r', word) :
    print(word)		# color, excolor, colsr
    
matchObj = re.findall('r..n[.]', 'ryan. ruin rain round. reign')
# ['ryan.']

^, $, \A, \Z : 대조, 역, 여집합

  • 시작 : ^, \A, 끝 : $, \Z는 re.MULTILINE 옵션을 설정하게 되면 문자열의 범위가 달라진다.
  • ^, $ : 행(개행문자까지) 시작, 끝과 일치. 행은 개행문자 개수 + 1개만큼 나오게 되고, 각 행마다 패턴을 찾는다.
  • \A, \Z : 문자열 시작, 끝과 일치
re.findall('\Aryan\d\Z', 'ryan1')		# ['ryan1']
re.findall('^ryan\d$', 'ryan1')			# ['ryan1']

re.findall('\A ryan\d\s\Z', ' ryan1 \n ryan2 \n rain1 \n ryan3 ')	# []
re.findall('^ ryan\d\s$', ' ryan1 \n ryan2 \n rain1 \n ryan3 ')		# []
re.findall('^ ryan\d\s$', ' ryan1 \n ryan2 \n rain1 \n ryan3 ', re.M)	# [' ryan1 ', ' ryan2 ', ' ryan3 ']
re.findall('^ ryan\d\s$', ' ryan1 \n ryan2 \n rain1 \n ryan3 ', re.MULTILINE)	# [' ryan1 ', ' ryan2 ', ' ryan3 ']

OR, 반복

| : 다자택일 ( OR )

re.findall('one|two|three', 'one four two three zero')		# ['one', 'two', 'three']

Star ( * )

    • 은 해당 위치에 해당 글자 0개 이상
a*c		# aac, aaaac, aaaaaaaaaaaaaaac -> True
		# acc, abc, asc			-> False
(ab)*c			# c, abc, ababc, abababababc	-> True
			# abbc, ac, abcc, c
for word in li :
  if re.search('col*r', word) :		# co(l*)r
    print(word)		# colr, cor, colllr

Dot ( . ) , Star ( * ) 혼합

    • 은 해당 위치에 아무 글자(.) 0개 이상
# .*은 0이상 글자
for word in li :
  if re.search('col.*r', word) :		# co(l.*)r
    print(word)		# color, colour, excolor, xcoloor, colr, colllr, colsr
  • 응용
regular_expressions = '<html><head><title>Title</title>'
print(len(regular_expressions))	# 32

print(re.match('<.*>', regular_expressions).span())		# (0, 32) : 맨 처음 위치와 맨 마지막 위치

print(re.match('<.*>', regular_expressions).group())	# group화한 해당 string ( str[0:32] )

Plus ( + )

    • 은 해당 위치에 해당 글자 1개 이상
ab+c		# abc, abbc, abbbc -> True
		# ac, acc, acbb	-> False

횟수 제한 ( {m, n}, ? )


wikidocs 정규표현식
특수문자, [], 문자집합, ^
OR, 반복

0개의 댓글