정규식 (Regular Expression)
Table Of Contents
- 반복 메타 문자
- Match (문자열 매치하기)
- Search (부분적으로 매치하기)
- substitute (대치)
- 최소 매칭
- 정규식 객체 사용하기
- SAMPLE (HTTP URL 매칭)
반복 메타 문자
반복 메타 문자 |
의미 |
예 |
* |
0회이상 반복 |
ca*는 ct,cat, caaaat등과 매치 |
+ |
1회이상 반복 |
ca+는 cat, caaaat등과 매치된다 |
? |
0회 혹은 1회 |
ca?t는 ct, cat와 매치된다 |
{m} |
m회 반복 |
ca{2}는 caa와 매치된다. |
{m,n} |
m회부터 n회까지 반복 |
ca{2,4}는 caat, caaat, caaaat와 매치 |
매칭 메타 문자
메타문자 |
의미 |
. |
줄바꿈 문자를 제외한 모든 문자와 매치된다. re.DOTALL모드로 사용하면 줄바꿈문자도 매치가능 |
^ |
1.문자열의 시작과 매치된다. re.MULTILINE모드에서는 각라인의 시작과 매치된다. 2.[]메타기호 안에서는 반대의 문자열을 취한다. [^5]는 5가아닌 문자이다. |
$ |
1.문자열의 마지막과 매치된다. 2.[]메타 기호안에서는 메타 기호로 사용되지 않고 순수한 $문자로 매치된다. |
[] |
문자 집합을 나타낸다.[abc]는 a, b, c중 한 문자를 의미한다. [a-c]와 같이 쓸수 있다. -는 범위를 나타낸다.[a-zA-Z0-9]는 영문자 숫자를 의미한다. |
| |
a|b는 a 또는 b의 의미이다 |
() |
정규식을 그룹으로 묶는다. |
- c.t는 cat, cbt, cct등과 매치된다.
- ^cat는 'cats and dogs'과 매치되지만, 'dogs and cats'와는 매치되지 않는다.
- c[^a]t는 cbt,cct, cdt등과 매치되지만, cat와는 매치되지 않는다.
- cat$는 'dogs and cats'와는 매치되지 않지만, 'a dot and a cat'와는 매치된다.
- c[abc]는 cat, cbt, cct와 매치된다.
- ca|bt는 ca, bt와 매치된다.
이스케이프 기호
분야 |
설명 |
\ |
역슬래쉬 문자 자체를 의미한다. |
\d |
모든 숫자와 매치한다.[0-9] |
\D |
숫자가 아닌 문자와 매치된다.[^0-9] |
\s |
화이트 스페이스 문자와 매치된다.[\t\n\r\f\v] |
\S |
화이트 스페이스 문자가 아닌것과 매치된다.[^\t\n\r\f\v] |
\w |
숫자 또는 문자와 매치된다.[a-zA-Z0-9] |
\W |
숫자 또는 문자가 아닌 것과 매칭된다.[^a-zA-Z0-9] |
\b |
단어의 경계를 나타낸다. 단어는 영문자 혹은 숫자의 연속문자열로 가정한다. |
\B |
\b의 반대로 단어의 경계가 아님을 나타낸다. |
Match (문자열 매치하기)
>>> import re
>>> m = re.match('[0-9]', '1234')
>>> m.group()
'1'
>>> m = re.match('[0-9]+', '1234')
>>> m.group()
'1234'
>>> m = re.match('[0-9]+', '1234 ') // 뒤에 공백도 매치한다.
>>> m.group()
Search(부분적으로 매치)
>>> re.search('\d+', ' 1034a ').group()
'1034'
substitute (대치)
정규식으로 찾은 단어를 다른 단어로 대치하는 것이다. XML의 숫자, 를 숫자, 로 어떻게 바꿀까? 아래 코드처럼 하면 된다. 간단히 설명하자면, 패턴의 (\d+,\d+) 이 837,773이되고, \1 은 group(1) 즉 837,773이 된다.
>>> str = '<tr><td>셋탑 수 (UNIQUE) </td><td>837,773</td></tr>'
>>> re.sub(r'<td>(\d+,\d+)', r'<td style="text-align: right;">\1', str)
'<tr><td>셋탑 수 (UNIQUE) </td><td style="text-align: right;">837,773</td></tr>'
비슷한 예로 아래처럼 함수명을 바꾸는 코드가 있는데, 여기서 \1 은 myfunc이다.
>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',
... r'static PyObject*\npy_\1(void)\n{',
... 'def myfunc():')
'static PyObject*\npy_myfunc(void)\n{'
JAVA 에선 대치를 어떻게 하는걸까? 예를 들어서, 10,000원 에서 컴마를 제거하여 10000원 으로 만들고 싶으면 어떻게? 아래 JAVA 코드처럼 하면 된다. replaceAll에서도 $1(group(1)) 을 쓸수있다니. 난 몰랐었다ㅠ
String str = ",20200325031326.702^CTPL46_muid|{EEC79781-DFE3-4060-A20A-05500F79C11C} HD일반 10,000원";
System.out.println (str.replaceAll(",([0-9]00)", "$1"));
결과물
,20200325031326.702^CTPL46_muid|{EEC79781-DFE3-4060-A20A-05500F79C11C} HD일반 10000원
최소 매칭
메타문자 *,+,?는 가능하면 많은 문자들을 포함시키려고 노력한다. 이것을 탐욕적인 매칭(Greedy Matchin)이라고 한다.
>>> re.search(r'href="(.*)"', '<a href="index.html">HERE</a><font size=10>').group(1)
'index.html">HERE</a><font size="10'
>>> re.search(r'href="(.*?)"', '<a href="index.html">HERE</a><font size=10>').group(1)
'index.html'
기호 |
의미 |
*? |
*와 같으나 문자열을 최소로 매칭한다. |
+? |
+와 같으나 문자열을 최소로 매칭한다. |
?? |
?와 같으나 문자열을 최소로 매칭한다. |
{m,n}? |
{m,n}과 같으나 문자열을 최소로 매칭한다. |
정규식 객체 사용하기
>>> p = re.compile(r'([_a-zA-Z]\w*)\s*=\s*(\d+)')
>>> m = p.match('a = 123')
>>> m.groups()
['a', '123']
>>> m.group(1)
'a'
HTTP URL 매칭
#!/usr/bin/python
import re
if __name__ == '__main__':
with open("log.txt") as f:
content = f.readlines()
dicts = {}
contents = ''
for line in content:
contents += line
regex = re.compile(r'impression=\W+(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)]\W+')
match_obj = regex.search(contents)
for url in match_obj.groups():
if dicts.has_key(url):
print ('URL duplicated!!! = {}'.format(url))
else:
dicts[url] = 1
print(match_obj.groups())