생각보다 자주쓰이는데 까먹어서, 계속 찾아보게 되는 정규표현식을 정리해보았다.
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가지
- 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'>
- 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'>
- 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']
- 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 옵션을 추가하면 정규표현식에 컴파일시 자동으로 제거되는 공백과 코멘트를 추가할 수 있게된다.(단, [] 안에 입력된 공백문자 제외)
정규식에서 /를 쓰려면
실제 코드에서는 ////를 써주면 된다
참고 :
'개발합시다. > 개발을 더 잘하기 위한 노력' 카테고리의 다른 글
2023 인프콘 후기 (0) | 2023.08.16 |
---|---|
2023 토스 NEXT 개발 챌린지 후기 (0) | 2023.08.16 |
코드리뷰 문화를 만들어보자. [총정리] (1) | 2022.08.18 |
Vue의 데이터 교환 3 [EventBus] (0) | 2022.08.12 |
Vue의 데이터 교환 2 [Vuex Store] (0) | 2022.08.12 |