[Python] 're'__정규식 연산 라이브러리

김명건·2021년 9월 30일
0
post-thumbnail
post-custom-banner

이 문서는 점프 투 파이썬을 기본 바탕으로 작성되었다.(복사하여 붙여 넣었다고 읽는다.)
추후 학습하거나 깨닳은 요령이 생긴다면 최신화하는 방향으로 한다.

0. 참고자료

점프 투 파이썬 - 정규표현식

1. 개요

정규표현식 - 위키백과

  • 정규표현식(정규식) : 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어
	컴퓨터 과학의 정규 언어로부터 유래하였으나 구현체에 따라서 정규 언어보다 더 
	넓은 언어를 표현할 수 있는 경우도 있으며, 심지어 정규 표현식 자체의 문법도
	여러 가지 존재하고 있다.

코딩을 하다보면 문자열을 조작해야 하는 경우가 생긴다. 이 때 문자열 자료형의 기능이나 내장 함수를 통해 수정하거나 관리할 수 있겠지만 특정한 단어를 찾아 바꾸거나 일정 패턴의 문자열을 제거한다던가 하는 작업엔 어려움이 따른다. 이를 해결하기 위해 정규표현식(정규식)을 사용하게 된다.

2. 정규표현식

1. 메타 문자

  • 메타문자 : 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자
    정규표현식에서 사용하는 메타 문자(meta chracters)는 다음과 같다.
	. ^ $ * + ? { } [ ] \ | ( )

1. 문자 클래스 : [ ] - ^ \d \D \s \S \w \W

1. 문자 클래스 [ ]

  • [ ] 문자 클래스 : [ ] 사이의 문자들과 매치의 의미
    ([ ] 사이에는 어떤 문자도 들어갈 수 있다.)
	$$ 정규식 [abc]와 문자열과의 매치 $$
	1. "a" : 정규식과 일치하는 문자 "a"가 있으므로 매치 O
	2. "before" : 정규식과 일치하는 문자인 "b"가 있으므로 매치 O
	3. "dude" : 정규식과 아무것도 일치하는 것이 없으므로 매치되지 않음 X

2. 하이픈 [-]

  • [ ] 안의 두 문자 사이에 하이픈-을 사용하면 두 문자 사이의 범위를 의미
	1. [a-zA-Z] : a ~ z 까지 그리고 A ~ Z 까지 모든 알파벳을 포함
	2. [0-9] : 0 ~ 9 까지의 모든 숫자

3. 서컴플렉스 [^]

  • [ ] 안에 ^ 메타 문자를 사용하면 반대(not)의 의미를 갖는다.
	1. [^0-9] : 숫자가 아닌 문자만 매치

4. 자주 사용하는 문자 클래스 표기법

  • 자주 사용하는 문자 클래스 : 자주 사용하는 정규식은 별도의 표기법이 존재한다.
	$$ 자주 사용하는 문자 클래스 $$
	1. \d : 숫자와 매치, [0-9]와 동일
	2. \D : 숫자가 아닌 것과 매치, [^0-9]와 동일
	3. \s : whitespace(공백문자)와 매치, [ \t\n\r\f\v]와 동일(맨 앞은 빈 칸(' ')의 공백 문자)
	4. \S : whitespace가 아닌 것과 매치, [^ \t\n\r\f\v]와 동일
	5. \w : 문자 + 숫자(alphanumeric)와 매치, [a-zA-Z0-9_]와 동일
	6. \W : 문자 + 숫자(alphanumeric)이 아닌 문자와 매치, [^a-zA-Z0-9_]와 동일
    
	대문자는 소문자 표현식의 반대임을 추측할 수 있다.

2. Dot '.'

  • . : 줄바꿈 문자인 \n을 제외한 모든 문자와 매치
    (정규식 작성 시 re.DOTALL 옵션을 준다면 \n문자와도 매치할 수 있다.)
	a.b = "a + 모든문자 + b"
	1. "aab" : "a + a(모든문자) + b"이므로 매치 O
	2. "a0b" : "a + 0(모든문자) + b"이므로 매치 O
	3. "abc" : "a"와 "b"사이에 어떤 문자라도 하나는 있어야 하지만 없으므로 매치되지 않음 X
  • [.] : 문자 클래스 내에 .만 존재한다면 모든 문자라는 의미가 아닌 . 그대로를 의미
	a[.]b = "a + . + b"
	1. "a.b" : "a + . + b"이므로 매치 O
	2. "a0b" : "a + 0(. 아님) + b"이므로 매치되지 않음 X

3. 반복 '*'

  • * : 반복을 의미 * 바로 앞에 있는 문자가 0개부터 무한대로 반복될 수 있음
    (반복 개수는 메모리 제한으로 2억개 정도만 가능하다고 한다.)
	ca*t
	1. "ct" : "a"가 0번 반복되므로 매치 O
	2. "cat" : "a"가 0번 이상 반복되므로 매치(1번) O
	3. "caaat" : "a"가 0번 이상 반복되므로 매치(3번) O

4. 반복 '+'

  • + : 반복을 의미 + 바로 앞에 있는 문자가 1개부터 무한대로 반복
	ca+t
	1. "ct" : "a"가 0번 반복되므로 매치 X
	2. "cat" : "a"가 1번 이상 반복되므로 매치(1번) O
	3. "caaat" : "a"가 1번 이상 반복되므로 매치(3번) O

5. 반복 {m,n} ?

  • {m,n} : m번부터 n번까지 반복
    (m 또는 n을 생략할 수 있다.)

1. {m}

  • {m} : 바로 앞에 오는 문자를 m회 반복
	ca{2}t
	1. "cat" : "a"가 2번 반복되지 않으므로 매치 X
	2. "caat" : "a"가 2번 반복되므로 매치 O

2. {m, n}

  • {m, n} : 바로 앞에 오는 문자를 m ~ n 회 반복
	ca{2,5}t
	1. "cat" : "a"가 1번만 반복되어 매치 X
	2. "caat" : "a"가 2번 반복되어 매치 O
	3. "caaaaat" : "a"가 5번 반복되어 매치 O

3. '?'

  • ? : 반복은 아니지만 비슷한 개념으로 {0,1}을 의미
	ab?c
	1. "abc" : "b"가 1번 사용되어 매치 O
	2. "ac" : "b"가 0번 사용되어 매치 O

6. '^','$'

  • ^ : 문자열의 시작으로부터 정규식을 만족해야 함을 의미
	^https:[a-z]+[.][a-z]+
	1. "http:google.com" : "http:"에서 "s"가 없기 때문에 매치 X
	2. "https:google.com" : "https:"가 맞고 뒤의 정규식을 만족하므로 매치 O
  • $ : 문자열의 끝을 의미
	[a-z]+ done[.]$
	1. "python is fun done" : "done"의 "."가 없기 때문에 매치 X
	2. "python is fun done." : 앞의 정규식을 만족하며 "done."을 만족하기 때문에 매치 O

7. '|'

  • | : or와 동일한 의미로 사용된다. A|BA 또는 B라는 의미
p = re.compile('Crow|Servo')
m = p.amatch('CrowHello')
print(m)
>> <re.Match object; span=(0, 4), match='Crow'>

8. '\A','\Z'

  • \A : ^와 동일하게 문자열의 처음과 매치됨을 의미한다.
    (re.MULITLINE 옵션을 사용할 경우에도 각 줄과 매치되는 것이 아닌 전체 문자열의 처음과 매치된다.)
p = re.compile("\Apython\s\w+", re.MULTILINE)

data = """python one
life is too short
python two
you need python
python three"""

print(p.findall(data))

// 이후 등장하는 MULTILINE(각 줄별로 매치함)를 사용해도 전체 문자열의 처음만 매치됨 //
>> ['python one']
  • \Z : $와 동일하게 문자열의 마지막과 매치된다.
    (\A와 마찬가지로 MULTILINE 옵션 사용 시에도 전체 문자열로부터 조사한다.)
p = re.compile("\w+\spython\Z", re.MULTILINE)

data = """first python
life is too short
second python
you need python
third python"""

print(p.findall(data))
>> ['third python']

9. '\b', '\B'

  • \b : 단어 구분자(Word boundary)이다. 단어는 whitespace에 의해 구분된다.
    (\b는 파이썬 리터럴 규칙에 의하면 백스페이스(BackSpace)를 의미하므로 단어 구분자임을 알려주기 위해 r'\bclass\b'처럼 Raw string으로 작성해야 한다.)
p = re.compile(r'\bclass\b')

// 양 쪽이 whitespace(공백문자)이며 "class"가 있으므로 매치 O //
print(p.search('no class at all'))
>> <re.Match object; span=(3, 8), match='class'>

// "class"가 있지만 양 쪽이 whitespace가 아니므로 매치 X //
print(p.search('the declassified algorithm'))
>> None

// "class"가 있지만 한 쪽이 whitespace가 아니므로 매치 X //
print(p.search('one subclass is'))
>> None
  • \B : \b와 반대의 경우이다. whitespace로 구분되지 않은 단어를 매치한다.
p = re.compile(r'\Bclass\B')

print(p.search('no class at all'))  
>> None

print(p.search('the declassified algorithm'))
>> <re.Match object; span=(6, 11), match='class'>

print(p.search('one subclass is'))
>> None

10. grouping : ( )(하위식), (?...) : (?P...) (?=...) (?!...)

1. ( )(하위식)

  • ( ) : ( )안의 문자열이 반복되는지 조사
p = re.compile('(ABC)+')
m = p.search('ABCABCABC OK?')

print(m)
>> <re.Match object; span=(0, 9), match='ABCABCABC'>

print(m.group())
>> ABCABCABC

2. group()

2-1. 기본적인 group의 사용

  • group() : ()를 사용하는 이유는 반복되는 문자 이외에도 매치된 문자열에서 특정 부분의 문자열만 뽑아내기 위해서이다.
// '( )'을 사용하지 않은 경우 //
p = re.compile(r"\w+\s+\d+[-]\d+[-]\d+")
m = p.search("park 010-1234-1234")

// 기본적으로 매치된 문자열을 돌려준다. //
print(m.group())
>> park 010-1234-1234
// 그룹화된 문자열이 없기 때문에 인덱스에러가 발생한다. //
print(m.group(1))
>> IndexError: no such group

// '( )'를 사용하여 grouping한 경우 //
p = re.compile(r"(\w+)\s+\d+[-]\d+[-]\d+")
m = p.search("park 010-1234-1234")

// 기본적으로 매치된 문자열을 돌려준다. //
print(m.group())
>> park 010-1234-1234
// '\w+''(\w+)'로 grouping 해주었기 때문에 //
// group의 첫 번째 인덱스가 문자열인 "park"를 나타낸다. //
print(m.group(1))
>> park
  • group 메서드의 인덱스

    group(인덱스)설명
    group(0)매치된 전체 문자열
    group(1)첫 번째 그룹에 해당되는 문자열
    group(2)두 번째 그룹에 해당되는 문자열
    group(n)n 번째 그룹에 해당되는 문자열
p = re.compile(r"(\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")

// 전화번호 부분을 grouping하여 group으로 뽑아내는 경우 //
print(m.group(2))
>> 010-1234-1234
// 그룹을 중첩 사용하는 것도 가능하다. //
// 중첩 시는 바깥쪽부터 시작하여 인덱스가 증가한다. //
print(m.group(3))
>> 010

2-2. grouping 문자열 재참조

  • ( )\1 : ( )로 그룹화된 문자열은 \n(1번 부터 시작하는 인덱스)메타 문자로 정규식 내에서 불러 사용할 수 있다.
// '(\b\w+)'를 `\1`로 재참조하여 사용하므로써 //
// "(group) + ' ' + group과 매치된 단어"와 매치 //
p = re.compile(r'(\b\w+)\s+\1')
str = p.search('Paris in the the spring').group()

// '(\b\w+)' == 'the', '\1' == 'the' //
print(str)
>> the the

// 여러 문자를 그룹화(grouping)했다면 `\n`을 통해 n 번째의 그룹을 참조할 수 있다. //

2-3. 정규식 확장문 (?...)

  • (?...) : 정규표현식의 확장 구문으로, 강력한 기능들을 사용할 수 있다.
구문설명
(?P<그룹명>...)'...'에 매치되는 문자열이 '그룹명'을 가짐
(?P=그룹명)'그룹명'의 값을 참조(정규식 내에서 재참조 시 사용)
(?=...)'...'을 포함하여 매치되는 문자열을 검색하지만 검색 결과에는 포함시키지 않음
(?!...)'...'을 포함하는 문자열의 경우 결과에서 제외

2-3-1. grouping 문자열에 이름 붙이기 (?P<name>...)

  • (?P<그룹명>...) : ( )내에서 ?P<그룹명>구문을 사용하면 이후 정규식에 매치되는 문자열을 해당 이름(변수명)으로 그룹화(grouping)할 수 있다.
    (그룹명은 정규식 안에서 재참조가 가능하다.)
// '(?P<name>\w+)' => '(\w+)'"name"의 그룹명을 붙임 //
p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")

// "name"의 그룹명을 가진 "park"를 결과로 돌려준다. //
print(m.group("name"))
>> park

// "word"를 정규식 내에서 재참조 //
p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
str = p.search('Paris in the the spring').group()

// (?P<word>\b\w+) => word = 'the', (?P=word) => 'the' // 
print(str)
>> the the

2-3-2. 긍정형 전방 탐색 (?=...)

  • (?=...) : ...를 포함하여 매치하지만 결과에서 ...를 제외
// (?=:) => ':'을 포함하여 검색하지만 결과에서 제외 //
p = re.compile(".+(?=:)")
m = p.search("http://google.com")

// '.+(?=:)' => http + ':' = "http" 제외 //
print(m.group())
>> http

2-3-3. 부정형 전방 탐색 (?!...)

  • (?!...) : ...의 매치 결과를 포함하는 결과를 제외
    (긍정형 전방 탐색((?=...))에서 작성이 어려운 정규식을 쉽게 사용할 수 있다.)
// (?!bat$|exe$) => "bat"이나 "exe"끝나는 것들은 제외 //
p = re.compile(r".*[.](?!bat$|exe$).*$", re.MULTILINE)

s = """data.db
python.exe
title.txt
seq.bat
server.js
"""

m = p.findall(s)

// "python.exe""seq.bat"가 제외된 결과 //
print(m)
>> ['data.db', 'title.txt', 'server.js']

3. re : python 정규식 라이브러리

1. re 모듈

  • re(regular expression) : python에서 정규표현식을 지원하기 위해 제공하는 모듈
    (파이썬 설치 시 자동으로 설치되는 기본(표준) 라이브러리이다.)
import re
p = re.compile('ab*') // 'ab*'를 컴파일한다

re.compile을 사용하여 정규표현식을 컴파일하고 돌려주는 객체(p)를 사용하여 이후 작업을 수행하게 된다.

  • 정규식을 컴파일할 때 특정 옵션을 주는 것도 가능하다.(이후에 다루기로 한다.)
  • 패턴(p)란 정규식을 컴파일한 결과

2. 정규식을 이용한 문자열 검색

  • 컴파일된 패턴 객체는 다음의 4가지 메서드를 가진다.
    |Method|목적|
    |:--:|:--:|
    |match()|문자열의 처음부터 정규식과 매치되는지 조사|
    |search()|문자열 전체를 검색하여 정규식과 매치되는지 조사|
    |findall()|정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려준다|
    |finditer()|정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려준다|
  • match, search는 정규식과 매치될 때 match 객체를 돌려주고, 아닐 경우 None을 돌려준다.
    • match 객체 : 정규식의 검색 결과로 돌려주는 객체
// 메서드 사용을 위한 패턴 //
import re
    p = re.compile('[a-z]+')

1. match

  • match : 문자열의 처음부터 정규식과 매치되는지 조사한다.
m = p.match("python")
print(m)

>> <re.Match object; span=(0, 6), match='python'>
  • "python"문자열이 [a-z]+에 부합하므로 match 객체를 돌려준다.
m = p.match("3 python")
print(m)

>> None
  • "3 python" 문자열의 3이 [a-z]+에 부합하지 않으므로 None을 돌려준다.
  • 일반적인 정규식 프로그램의 흐름
p = re.compile(정규식)
m = p.match('string goes here')

// match의 결과값이 있을 경우만 작업을 수행 //
if m:
	print('Match found: ', m.group())
else:
	print('No match')
  • search : 문자열 전체에서 매치되는 경우를 조사한다.
m = p.search("python")
print(m)

>> <re.Match object; span=(0, 6), match='python'>
m = p.search("3 python")
print(m)

>> <re.Match object; span=(2, 8), match='python'>
  • match를 성공했을 때와 같은 객체를 돌려준다.

3. findall

  • findall : 정규식과 매치된 문자열들을 리스트 형식으로 돌려준다.
result = p.findall("life is too short")
print(result)

>> ['life', 'is', 'too', 'short']

4. finditer

  • finditer : findall과 동일하지만 결과로 반복 가능한 객체(iterator object)를 돌려준다.
    (반복 가능한 객체가 포함하는 각각의 요소는 match 객체이다.)
result = p.finditer("life is too short")
print(result)

>> <callable_iterator object at 0x000002AF97B74E50>

for r in result:
	print(r)

>> <re.Match object; span=(0, 4), match='life'>
>> <re.Match object; span=(5, 7), match='is'>
>> <re.Match object; span=(8, 11), match='too'>
>> <re.Match object; span=(12, 17), match='short'>

3. match 객체의 메서드

method목적
group()매치된 문자열을 돌려준다
start()매치된 문자열의 시작 위치를 돌려준다
end()매치된 문자열의 끝 위치를 돌려준다
span()매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다.
  • match로 받은 객체일 경우
import re
p = re.compile('[a-z]+')
m = p.match("python")
m.group()
>> 'python'
m.start() // match 메서드는 시작부터 조사하기 때문에 start는 항상 0이다.
>> 0
m.end()
>> 6
m.span()
>> (0, 6)
  • search로 받은 객체일 경우
m = p.match("3 python")
m.group()
>> 'python'
m.start()
>> 2
m.end()
>> 8
m.span()
>> (2, 8)

[모듈 단위로 수행하기]

지금까지 re.compile을 사용하여 컴파일된 패턴 객체를 사용했다면
re 모듈은 보다 축약한 형태로 사용할 수 있는 방법을 제공한다.

// 기본적인 컴파일된 패턴과 매치된 객체 //
p = re.compile('[a-z]+')
m = p.match("python")

// 모듈 내에서 축약시켜 사용하는 예 //
m = re.match('[a-z]+', "python")

컴파일과 메서드를 한 번에 수행할 수 있지만, 한 번 만든 패턴 객체를
여러번 사용해야 할 때는 re.compile을 사용하는 것이 편하다.

4. 컴파일 옵션

  • 정규식을 컴파일할 때 다음 옵션을 사용할 수 있다.
    (re.DOTALL처럼 전체 옵션을 사용하거나 re.S처럼 약어를 사용할 수 있다.)
option(약어)기능
DOTALL(S)'.'이 줄바꿈 문자를 포함하여 모든 문자와 매치할 수 있도록 한다
IGNORECASE(I)대소문자에 관계없이 매치할 수 있도록 한다
MULTILINE(M)여러줄과 매치할 수 있도록 한다('^','$'메타문자의 사용과 관계가 있는 옵션이다)
VERBOSE(X)verbose 모드를 사용할 수 있도록 한다(정규식을 보기 편하게 만들 수 있고 주석 등을 사용할 수 있게된다)

1. DOTALL, S

  • DOTALL(S) : . 사용 시 줄바꿈 문자(\n)도 포함하여 매치한다.
import re

// 기본 컴파일 시 //
p = re.compile('a.b')
m = p.match('a\nb')
print(m)
>> None

// DOTALL 옵션 사용 시 //
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)
>> <re.Match object; span=(0, 3), match='a\nb'>

2. IGNORCASE, I

  • IGNORECASE(I) : 대소문자 구별 없이 매치를 수행하는 옵션
p = re.compile('[a-z]+', re.I)
p.match('python')
>> <re.Match object; span=(0, 6), match='python'>
p.match('Python')
>> <re.Match object; span=(0, 6), match='Python'>
p.match('PYTHON')
>> <re.Match object; span=(0, 6), match='PYTHON'>

3. MULTILINE, M

  • MULTILINE(M) : ^, $와 연관된 옵션으로, ^ 또는 $ 옵션을 각 라인별로 적용시키고 싶을 경우 사용한다.
    (각 줄마다 사용되므로 줄바꿈 문자(\n)가 있는 경우에 사용한다.)
import re

// 기본적인 '^'를 사용한 정규식 매치 //
p = re.compile("^python\s\w+")

data = """python one
life is too short
python two
you need python
python three"""

print(p.findall(data))

>> ['python one']

// MULTILINE 옵션을 이용한 정규식 매치 //
p = re.compile("^python\s\w+", re.MULTILINE)

data = """python one
life is too short
python two
you need python
python three"""

print(p.findall(data))

>> ['python one', 'python two', 'python three']

4. VERBOSE, X

  • VERBOSE(X) : 정규식을 주석 또는 줄 단위로 구분하여 사용 가능(가독성 증가)
  • 문자열에 사용된 whitespace는 컴파일할 때 제거된다. 그리고 줄 단위로 #기호를 사용하여 주석문을 작성할 수 있다.
    (단 [] 안에 사용한 whitespace는 제외된다.)
// VERBOSE 적용 전 정규식 //
charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')

// VERBOSE 적용 후 사용 가능한 정규식 //
charref = 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)

5. 백슬래시 문제

  • 정규 표현식을 파이썬에서 사용하는 경우 \는 혼란을 준다.
// "\section"문자열을 찾기 위한 정규식 //
	\section
==> '\s'문자가 whitespace로 해석되어 의도한 매치 불가
	\section : [ \t\n\r\f\v]ection 과 동일

// '\'를 문자로 인식하게 하기 위해 '\\'(두 개를 사용) 이스케이프 처리를 한다. //
	\\section
==> 파이썬 정규식 엔진에선 문자열 리터럴 규칙에 따라 '\\'이 '\'로 변경된다.
	\\section : \section으로 변경됨(파이썬 문자열 리터럴 규칙에 따라)
	(이 문제는 파이썬에서만 발생한다.)
    
// '\\'를 문자로 전달하기 위해선 '\\\\'를 사용해야 한다. ==> 비효율 //
// 파이썬 정규식의 'Raw String'규칙을 이용하여 처리할 수 있다. //
	'\\\\section' == r'\\section'
==> ex) p = re.compile(r'\\section')

// 백슬래시를 사용하지 않는 정규식이라면 'r'의 유무에 상관없이 동일한 정규식이 된다. //

6. 문자열 바꾸기

1. re.sub()

  • re.sub(바꿀 문자열, 대상 문자열, count=n(바꿀 횟수)) : 대상 문자열에서 컴파일된 패턴에 해당하는 문자를 바꿀 문자열로 바꾼다. count가 있다면 그 횟수만큼만 바꾼다.
p = re.compile('(blue|white|red)')
s = p.sub('colour', 'blue socks and red shoes')

// "blue", "red" => "colour" //
print(s)
>> 'colour socks and colour shoes'

// 'count'를 사용한 경우 //
s = p.sub('colour', 'blue socks and red shoes', count=1)

// 첫 번째인 "blue""colour"로 바뀜 //
print(s)
>> 'colour socks and red shoes'

2. sub()와 참조구문 사용

  • sub()를 사용할 때 참조구문을 사용할 수 있다.
// '그룹명'을 통한 참조와 sub() 활용 //
p = re.compile(r"(?P<name>\w+)\s+(?P<phone>(\d+)[-]\d+[-]\d+)")

// '\g<그룹명>'을 통해 sub()에서 사용 가능하다. //
print(p.sub("\g<phone> \g<name>", "park 010-1234-1234"))
>> 010-1234-1234 park

// 그룹 '인덱스'를 통한 참조와 sub() 활용 //
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

3. sub()에 매개변수로 함수 넣기

  • sub()의 첫 번째 매개변수로 함수를 넣을 수 있다.
// 10진수를 16진수로 바꾸는 함수 //
def hexrepl(match):
	value = int(match.group())
	return hex(value)

// sub()의 매개변수로 함수를 넘겨 10진수를 16진수로 변환 //ㅁ
p = re.compile(r'\d+')
s = p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
print(s)
>> 'Call 0xffd2 for printing, 0xc000 for user code.'

7. Greedy vs Non-Greedy

  • Greedy : 같은 형식의 문자열일 경우 해당되는 모든 것이 매치된다.
// "<html>"만을 매치하기 어렵다 //
s = '<html><head><title>Title</title>'
print(len(s))
>> 32
print(re.match('<.*>', s).span())
>> (0, 32)
print(re.match('<.*>', s).group())
>> <html><head><title>Title</title>
  • ?(Non-Greedy) : ? non-greedy 문자로 가능한 한 최소한의 반복을 수행하도록 도움
s = '<html><head><title>Title</title>'
print(re.match('<.*?>', s).group())
>> <html>

print(re.findall('<.*?>', s))
>> ['<html>', '<head>', '<title>', '</title>']
post-custom-banner

0개의 댓글