출처 : https://blog.hexabrain.net/202

생각보다 자주쓰이는데 까먹어서, 계속 찾아보게 되는 정규표현식을 정리해보았다.

1. 메타문자 (원래 의미가 아닌 새로운 의미)

1-1. [ ] 문자 클래스

  • 문자 클래스(character class)인 [ ].  "[ ] 사이의 문자들과 매치"라는 의미를 갖는다.
[abc] # # abc 중 하나와 매치
  • [ ] 안에 - 를 사용하면 두 문자 사이의 범위를 뜻한다.
[a-zA-Z] : 알파벳 모두
[0-9] : 숫자
  • [자주 사용하는 문자 클래스]
    • \\d - 숫자와 매치, [0-9]와 동일한 표현식이다.
    • \\D - 숫자가 아닌 것과 매치, [^0-9]와 동일한 표현식이다.
    • \\w - 문자+숫자(alphanumeric)와 매치, [a-zA-Z0-9_]와 동일한 표현식이다.
    • \\W - 문자+숫자(alphanumeric)가 아닌 문자와 매치, [^a-zA-Z0-9_]와 동일한 표현식이다.
    • \\s - whitespace 문자와 매치, [ \\t\\n\\r\\f\\v]와 동일한 표현식이다. 맨 앞의 빈 칸은 공백문자(space)를 의미한다.
    • \\S - whitespace 문자가 아닌 것과 매치, [^ \\t\\n\\r\\f\\v]와 동일한 표현식이다.
  • [ ] 안의 ^는 Not을 뜻한다.
[^0-9] # 숫자를 제외한 문자만 매치
[^abc] # a, b, c를 제외한 모든 문자와 매치

1-2. 모든 문자 .

  • 정규 표현식의 Dot(.) 메타 문자는 줄바꿈 문자인 \\n을 제외한 모든 문자와 매치됨을 의미
a.b # a + 모든 문자 + b를 뜻한다.
  • 원래 . 으로 사용하고 싶으면 [ ] 에 넣으면 된다.
a[.]b #a.b만 가능

1-3. 반복문자 *

  • 0~무한대 반복은 * 을 이용하면 된다.
lo*l # looooool도 매치됨
  • 1~무한대 반복은 +를 이용하면 된다.
lo+l # loool매치 but, ll는 매치안됨
  • 0~1 반복은 ?을 이용하면 된다.
lo?l #ll, lol매치 but loool은 매치 안됨
  • 반복 횟수 지정은 { } 를 이용하면 된다. - {m,n}은 m번에서 n번 반복까지 허용
lo{3,5}l # loool, looool, loooool만 매치

1-4. ETC

  • |은 or과 같은 의미이다. → 둘 중하나와 매치
a|b|c #a, b, c 중아무거나 다 매치 abc도 가능
  • 문자열의 처음과 매치하기 ^
^a # a로 시작하는 문자열만 매치함

@ [^]와는 다른 의미임

  • 문자열의 제일 마지막과 매치 $
a$ #마지막 글자가 a여야 매치

 

# 조건표현식

  • 표현식1(?=표현식2): 표현식1 뒤의 문자열이 표현식2와 매치되면 표현식1 매치.

'hello(?=world)' # hello 뒤에 world가 있으면 hello를 매치

  • 표현식1(?!표현식2): 표현식1 뒤의 문자열이 표현식2와 매치되지 않으면 표현식1 매치.

'hello(?!world)' # hello 뒤에 world가 없으면 hello를 매치

  • (?<=표현식1)표현식2: 표현식2 앞의 문자열이 표현식1과 매치되면 표현식2 매치.

'(?<=hello)world' # world 앞에 hello가 있으면 world를 매치

  • (?<!표현식1)표현식2: 표현식2 앞의 문자열이 표현식1과 매치되지 않으면 표현식2 매치.

'(?<!hello)world' # world 앞에 hello가 없으면 world를 매치


1-5. 정규표현식 모듈

Python 에서는 re 모듈을 통해 정규표현식을 사용한다.

import re

compile 정규표현식 컴파일

re.compile() 명령을 통해 정규표현식을 컴파일하여 변수에 저장한 후 사용할 수 있다.

변수이름 = re.compile('정규표현식')

정규표현식을 컴파일하여 변수에 할당한 후 타입을 확인해보면 _sre.SRE_Pattern 이라는 이름의 클래스 객체인 것을 볼 수 있다.

p = re.compile('[abc]')
print(type(p))

1-6. 정규표현식 매치 검색 함수 4가지

  1. Match : 시작부터 일치하는 패턴 찾기
p.match('aaaaa')
<_sre.SRE_Match object; span=(0, 5), match='aaaaa'>

p.match('bbbbbbbbb')
<_sre.SRE_Match object; span=(0, 9), match='bbbbbbbbb'>

p.match('1aaaa')
None

p.match('aaa1aaa')
<_sre.SRE_Match object; span=(0, 3), match='aaa'>
  1. Search : 전체 문자열에서 첫번째 매치 찾기
p.search('aaaaa')
<_sre.SRE_Match object; span=(0, 5), match='aaaaa'>

p.search('11aaaa')
<_sre.SRE_Match object; span=(2, 6), match='aaaa'>

p.search('aaa11aaa')
<_sre.SRE_Match object; span=(0, 3), match='aaa'>

p.search('1aaa11aaa1')
<_sre.SRE_Match object; span=(1, 4), match='aaa'>
  1. Findall : 모든 매치를 찾아 리스트로 변환
p.findall('aaa')
['aaa']

p.findall('11aaa')
['aaa']

p.findall('1a1a1a1a1a')
['a', 'a', 'a', 'a', 'a']

p.findall('1aa1aaa1a1aa1aaa')
['aa', 'aaa', 'a', 'aa', 'aaa']
  1. Finditer : 모든 매치를 찾아 반복가능 객체로 반환
p.finditer('a1bb1ccc')
<callable_iterator object at 0x7f850c4285f8>

f_iter = p.finditer('a1bb1ccc')
for i in f_iter:
    print(i)

1-7. 매치 객체의 메서드

패턴 객체의 메서드를 통해 리턴된 매치 객체는 아래와 같은 정보를 담고 있다.

<_sre.SRE_Match object; span=(매치 시작지점 인덱스, 매치 끝지점 인덱스), match='매치된 문자열'>

매치 객체는 내부 정보에 접근할 수 있는 네 가지 메서드를 제공한다.

group() 매치된 문자열 출력
start() 매치 시작지점 인덱스 출력
end() 매치 끝지점 인덱스 출력
span() (start(), end())를 튜플로 출력
p = re.compile('[a-z]+')
result = p.search('1aaa11aaa1')
print(result)

위의 코드를 실행하면 아래의 매치 오브젝트를 얻는다.

<_sre.SRE_Match object; span=(1, 4), match='aaa'>

매치 객체의 메서드를 실행한 결과는 아래와 같다.

result.group()
aaa

result.start()
1

result.end()
4

result.span()
(1, 4)

1-8. 그룹화

정규표현식을 () 안에 넣으면 그 부분만 그룹화된다. groups 메서드를 통해 그룹들을 튜플 형태로 리턴 할 수 있다.

p = re.search('(hello)(world)', 'helloworld') # 정규표현식 hello와 world의 매치 결과를 각각 그룹화하였다
grouping = p.groups()
print(grouping)

('hello', 'world') # 각 그룹의 매치 결과가 튜플로 묶여서 리턴됨

group 메서드를 통해 각 그룹을 호출할 수 있다.

p.group() # 인자를 넣지 않으면 전체 매치 결과 리턴
helloworld

p.group(0) # group()와 같다
helloworld

p.group(1) # 1번 그룹 매치 결과 리턴
hello

p.group(2) # 2번 그룹 매치 결과 리턴
world

1-9. 컴파일 옵션

정규표현식을 컴파일 할 때 옵션을 지정해줄 수 있다.

변수이름 = re.compile('정규표현식', re.옵션)


DOTALL, S

.은 줄바꿈 문자 \\n 를 제외한 모든 것과 매치된다. 컴파일 할 때 re.DOTALL 또는 re.S 옵션을 넣어주면 \\n 까지 매치되도록 할 수 있다.

p = re.compile('.') # 옵션 없음
result = p.findall('1a\\nbc')
print(result)
['1', 'a', 'b', 'c'] # \\n이 매치되지 않음

p = re.compile('.', re.DOTALL) # re.DOTALL 옵션 추가
result = p.findall('1a\\nbc')
print(result)
['1', 'a', '\\n', 'b', 'c'] # \\n까지 매치


IGNORECASE, I

re.IGNORECASE 또는 re.I 옵션을 넣어주면 대소문자를 구별하지 않고 매치된다.

p = re.compile('[a-z]') # 소문자만 매치
result = p.findall('aAbB')
print(result)
['a', 'b']

p = re.compile('[a-z]', re.IGNORECASE) # re.IGNORECASE 옵션 추가
result = p.findall('aAbB')
print(result)
['a', 'A', 'b', 'B'] # 소문자와 대문자 모두 매치


MULTILINE, M

re.MULTILINE 또는 re.M 옵션을 넣어주면 여러 줄의 문자열에 ^ 와 $ 를 적용할 수 있다.

text = '''student-1-name: James
student-2-name: John
student-3-name: Jordan
teacher-1-name: Mike
student-5-name: John'''
p = re.compile('^student.*') # 뒤따라 오는 문자 종류와 개수에 상관없이 student로 시작하는 문자열 매치 
result = p.findall(text)
print(result)
['student-1-name: James'] # 첫 줄만 매치되었다.

p = re.compile('^student.*', re.MULTILINE) # re.MULTILINE 옵션 추가
result = p.findall(text)
print(result)
['student-1-name: James', 'student-2-name: John', 'student-3-name: Jordan', 'student-5-name: John']
# student로 시작하는 모든 줄이 매치되었다.

p = re.compile('.*John$') # John으로 끝나는 문자열 매치
result = p.findall(text)
print(result)
['student-5-name: John'] # 가장 마지막 줄만 매치되었다

p = re.compile('.*John$', re.MULTILINE) # re.MULTILINE 옵션 추가
result = p.findall(text)
print(result)
['student-2-name: John', 'student-5-name: John'] # John으로 끝나는 모든 줄이 매치됨


VERBOSE, X

re.VERBOSE 또는 re.X 옵션을 주면 좀 더 가독성 좋게 정규표현식을 작성할 수 있게 된다. 아래의 두 표현식은 동일하게 작동한다.

p = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
p = 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) # re.VERBOSE 옵션 추가

re.VERBOSE 옵션을 추가하면 정규표현식에 컴파일시 자동으로 제거되는 공백과 코멘트를 추가할 수 있게된다.(단, [] 안에 입력된 공백문자 제외)

정규식에서 /를 쓰려면

실제 코드에서는 ////를 써주면 된다

 

 


참고 :

[Python 문법] 정규표현식 (Regular Expressions)

점프 투 파이썬

+ Recent posts