List
- 정규 표현식
- 정규 표현식 I
- 정규 표현식 II
+, *, [], {} |, ^, $, \A, \Z, \b, \Bzerowidth 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())
httpfoo.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>