List
- 정규 표현식
- 정규 표현식 I
- 정규 표현식 II
+
, *
, []
, {}
|
, ^
, $
, \A
, \Z
, \b
, \B
zerowidth assertions
|
:or
과 동일한 의미A | B
= A 또는 B 라는 의미>>> p = re.compile('Crow|Servo')
>>> m = p.match('CrowHello')
>>> print(m)
<re.Match object; span=(0, 4), match='Crow'>
^
: 문자열의 맨 처음과 일치>>> print(re.search('^Life', 'Life is too short')) # life가 문자열이 맨앞에 위치 했기 때문에 매치
<re.Match object; span=(0, 4), match='Life'>
>>> print(re.search('^Life', 'My Life')) # life 문자열이 뒤에 위치했기 때문에 매치불가
None
$
: 문자열의 맨 끝과 일치 (^
와 반대)>>> print(re.search('short$', 'Life is too short')) # short가 문자열이 맨뒤에 위치 했기 때문에 매치
<re.Match object; span=(12, 17), match='short'>
>>> print(re.search('short$', 'Life is too short, you need python')) # short가 문자열 맨뒤에 위치 하지 않음
None
\A
: 문자열의 처음과 매치 (^
과 동일한 의미)
re.MULTILINE
옵션을 사용할 경우 달라짐
^
은 각 줄의 문자열의 처음과 매치\A
는 전체 문자열의 처음과 매치(줄 상관 없음)
\Z
: 문자열의 끝과 매치 ($
과 동일한 의미)
re.MULTILINE
옵션을 사용할 경우 달라짐
$
은 각 줄의 문자열의 끝과 매치\Z
는 전체 문자열의 끝과 매치(줄 상관 없음)
\b
: 단어 구분자(Word boudnary)이며, whitespace
로 구분한다>>> p = re.compile(r'\bclass\b') # 압뒤가 whitespace로 구분된 class라는 단어와 매치
>>> print(p.search('no class at all')) #그에따라 class와 매치
<re.Match object; span=(3, 8), match='class'>
>>> print(p.search('the declassified algorithm')) # class 는 있지만 앞뒤 whitespace가 없기 때문에 매치 실패
None
>>> print(p.search('one subclass is')) # class뒤에만 whitespace있고 앞에는 없기때문에 매치 실패
None
[
\b
사용시 주의해야할 점]
\b
는 파이썬 리터럴 규칙에 의하면 백스페이스(BackSpace)를 의미
- 단어 구분자라는걸 알려주기 위해
r'
(raw string) 꼭 사용
\B
: 입력된 문자 앞뒤에 문자가 있어야 한다(whitespace 노 !)\b
와 반대>>> print(p.search('no class at all')) # 앞뒤에 whitespace이 있음
None
>>> print(p.search('the declassified algorithm')) # 앞뒤에 whitespace이 없기 때문에 매치
<re.Match object; span=(6, 11), match='class'>
>>> print(p.search('one subclass is')) # 뒤에 whitespace이 있음
None
( )
를 사용한다.(ABC)+
>>> p = re.compile('(ABC)+') # ABC 가 1번 이상 반복하는것들 매칭 . !
>>> m = p.search('ABCABCABC OK?') # 요기 있네 . .
>>> print(m)
<re.Match object; span=(0, 9), match='ABCABCABC'>
>>> print(m.group())
ABCABCABC
>>> p = re.compile(r"\w+\s+\d+[-]\d+[-]\d+")
>>> m = p.search("park 010-1234-1234")
\w+
= 이름
\s+
= " "(공백)
\d+
[-]
\d+
[-]
\d+
= 번호
이름부분인 \w
에 그루핑을 해서 \w
만 뽑아 오자
>>> p = re.compile(r"(\w+)\s+\d+[-]\d+[-]\d+") # \w 그루핑 진행
>>> m = p.search("park 010-1234-1234")
>>> print(m.group(1)) # group(인덱스)을 사용해서 출력
park
[group(인덱스)의 활용]
group(0)
: 매치된 전체 문자열group(1)
: 첫 번째 그룹에 해당되는 문자열group(2)
: 두 번째 그룹에 해당되는 문자열group(n)
: n 번째 그룹에 해당되는 문자열
(\d+[-]\d+[-]\d+)
에 그루핑을 해서 뽑아 오자>>> p = re.compile(r"(\w+)\s+(\d+[-]\d+[-]\d+)") # 그루핑 완료
>>> m = p.search("park 010-1234-1234")
>>> print(m.group(2)) # group(1) = (\w) / group(2) = (\d+[-]\d+[-]\d+)
010-1234-1234
(\b\w+)\s+\1
= (그룹) + " " + 그룹
\1
첫 번째 그룹을 가리킨다\2
는 두 본째 그룹을 가리키겠지>>> p = re.compile(r'(\b\w+)\s+\1')
>>> p.search('Paris in the the spring').group()
'the the'
(?P<그룹명>...)
(\w+)
-> (?P<name>\w+)
(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+) # \w 그루핑을 을 name으로 이름 지음
>>> p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)")
>>> m = p.search("park 010-1234-1234")
>>> print(m.group("name")) # 인덱스가 아닌 그루핑의 이름인 name을 검색
park
(?P=그룹이름)
사용(?P<word>\b\w+)\s+(?P=word)
(?P=word)
로 재참조>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)') # word 그루핑을 재참조
>>> p.search('Paris in the the spring').group()
'the the'
(?=...)
) - ...
에 해당되는 정규식과 매치되어야 하며 조건이 통과되어도 문자열이 소비되지 않는다.(?!...)
) - ...
에 해당되는 정규식과 매치되지 않아야 하며 조건이 통과되어도 문자열이 소비되지 않는다.*>>> p = re.compile(".+:")
>>> m = p.search("http://google.com")
>>> print(m.group())
http:
(?=...)
...
부분이 검색에는 포함되지만 검색 결과에는 제외 된다.>>> p = re.compile(".+(?=:)") # 기존 패턴 첫번째 줄 : 를 (?=:) 로 바꿨다
>>> m = p.search("http://google.com")
>>> print(m.group())
http
foo.bar
, autoexec.bat
, sendmail.cf
파일 중 .bat
파일을 제외시켜보자..*[.].*$ = 파일 이름 + . + 확장자
.*[.][^b].*$
- 불가.*[.]([^b]..|.[^a].|..[^t])$
- 불가|
사용, 확장자의 첫 번째 문자가 b가 아니거나 두 번째 문자가 a가 아니거나 세 번째 문자가 t가 아닌 경우를 의미foo.bar
는 제외되지 않고, autoexec.bat
은 제외된다.sendmail.cf
를 포함하지 못함...*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$
-가능?
는 바로 앞 문자가 있어도 되고 없어도되고 임.여기서
.bat
파일말고.exe
파일도 제외 해야한다면 ?> 부정형 전방 탐색 사용 해보자 ! ! ! ! ! ! !
(?!...)
...
부분이 검색에 포함되지 않고 검색 결과에서도 제외 된다.위의 정규식을 쉽고 짧게 줄일 수 있다.
.*[.](?!bat$).*$
= .*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$
.exe
파일 또한 제외하라는 조건을 쉽게 추가 할 수 있다.
.*[.](?!bat$|exe$).*$
sub(바꿀 문자열(replacement),바꿀 대상 문자열, count=#)
sub 메서드 사용
>>> p = re.compile('(blue|white|red)')
>>> p.sub('colour', 'blue socks and red shoes') #"blue socks and red shoes"에서 "blue" 또는 "white" 또는 "red" 를 "colour" 바꾼다.
'colour socks and colour shoes' # blue 와 red 가 colour로 바뀌었다
>>> p.sub('colour', 'blue socks and red shoes', count=1)
'colour socks and red shoes' # count=1에 따라 1번만 실행
[subn 메서드]
- sub메서드와 동일하지만 결괏값을 튜플로 돌려준다.
- 튜플의 첫 번째 요소는 변경된 문자열이고, 두 번째 요소는 바꾸기가 발생한 횟수
(변경된 문자열, 바꾸기가 발생한 횟수)
>> p = re.compile('(blue|white|red)') >> p.subn( 'colour', 'blue socks and red shoes') ('colour socks and colour shoes', 2) # 바뀐 문자열, blue와 red가 바뀌었으니 2를 출력
\g<그룹이름>
>>> p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")
>>> print(p.sub("\g<phone> \g<name>", "park 010-1234-1234")) # 기존 순서 name그룹 phone그룹 -> phone그룹 name 그룹 해줘라
010-1234-1234 park # 기존 park 010-1234-1234 에서 출력된 값같이 바뀌었다.
>>> p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")
>>> print(p.sub("\g<2> \g<1>", "park 010-1234-1234")) # 이름이 아닌 그루핑 번호를 써도 된다
010-1234-1234 park # 동일한 값이 나오는걸 볼 수 있다.
>>> def hexrepl(match): # hexrepl 함수는 match 객체(위에서 숫자에 매치되는)를 입력으로 받아,
value = int(match.group())
return hex(value) # 16진수로 변환하여 돌려주는 함수
>>> p = re.compile(r'\d+')
>>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.') # sub의 첫 번째 매개변수로 함수를 사용할 경우 사용된 함수의 첫 번째 매개변수에는 정규식과 매치된 match 객체가 입력 -> int()로 인해 'Call 65490 for printing, 49152 for user code.' 의 숫자 부분만 해당된다. 이 문자열의 숫자를 받아 16진법을 으로 돌려줌
매치된 match 객체가 입력
'Call 0xffd2 for printing, 0xc000 for user code.'
>>> s = '<html><head><title>Title</title>'
>>> len(s)
32
>>> print(re.match('<.*>', s).span())
(0, 32)
>>> print(re.match('<.*>', s).group())
<html><head><title>Title</title>
?
*?
, +?
, ??
, {m,n}?
>>> print(re.match('<.*?>', s).group())
<html>