
Regular Expression : re 요약
정규표현식(正規表現式, Regular Expression)은
- 문자열을 처리하는 방법 중의 하나로
- 특정한 조건의 substring(문자열)을 'searching(검색)'하거나 'substition(치환)'하는 과정을
- 특정 문자열의 pattern을 기술하는 expression(표현식)을 이용하여
매우 간편하게 처리 할 수 있도록 해준다.
0. 주요 Tasks
re를 통해 수행되는 것은 크게 다음의 세가지임.
- searching
- splitting
- replacing
이들 모두 특정 substring pattern에 대한 matching을 사용한다:
- matching되는 문자열 검색(존재유무 및 위치)
- matching되는 문자열 기준으로 분리
- mathcing되는 문자열 변경
즉, matching, searching, splitting, replacing을 하는 방법에 대한 이해를 하면 re를 효과적으로 사용가능하다.
1. re.Pattern: compiled pattern
Python에서는 matching에 사용할 expression(패턴)을 str로 사용하기도 하지만,
다음과 같이 이를 미리 compile해두고 그 결과값인 패턴을 재사용할 수 있다.
이 경우에 보다 수행속도가 올라간다. (동작 결과는 같음)
import re
# 기본 동작
compiledPattern1 = re.compile(r"hello", flags=0)
# 대소문자 구분 없이
compiledPattern2 = re.compile(r"hello", flags=re.I)
# 여러 플래그 함께 사용 (대소문자 무시 + multiline)
compiledPattern3 = re.compile(r"hello", flags=re.I | re.M)
사용되는 주요 flag를 간단히 살펴보면 다음과 같음.
0: flag 없이 컴파일하겠다는 의미임(기본모드로 사용하겠다는 의미)re.I: Ignores character case.re.M: multiline 으로 동작.
여러 flag를 동시에 사용하려면 이들을 bitwise or 처리한 값을 argument로 할당하면 됨.
반환값의 class는 re.Pattern 이며 다음의 methods를 가짐.
search(target_str): 문자열에서 패턴을 검색하여 매칭되는 경우re.Match객체를 반환.match(target_str): 문자열 시작부분이 패턴과 매칭되는지 확인하고 매칭시re.Match객체를 반환.fullmatch(target_str): 문자열 전체가 패턴과 일치하는지 확인.findall(target_str): 모든 일치 항목을list객체로 반환.finditer(target_str): 모든 일치 항목을iterable객체로 반환.sub(sub_str, target_str): 패턴과 매칭되는 항목을 다른 문자열로 치환.split(target_str): 패턴을 기준으로 문자열을 분할하여list객체로 반환.
다음은 이들의 동작을 확인할 수 있는 간단한 code snippet임.
import re
# 패턴 컴파일 (단어 'apple'이 포함된 부분을 찾는 패턴, 대소문자 구분 없음)
pattern = re.compile(r"apple", flags=re.I) # re.I = 대소문자 무시
text = "Apple pie and pineapple are tasty. I like apples."
# 1. search(): 첫 번째 매칭 결과만 반환 (re.Match 객체)
match = pattern.search(text)
print("search:", match.group() if match else "No match")
# 2. match(): 문자열의 시작에서만 매칭을 시도
match_start = pattern.match(text)
print("match:", match_start.group() if match_start else "No match at start")
# 3. fullmatch(): 전체 문자열이 패턴과 정확히 일치할 때만 성공
full = pattern.fullmatch(text)
print("fullmatch:", full.group() if full else "No full match")
# 4. findall(): 모든 매칭 결과를 리스트로 반환
all_matches = pattern.findall(text)
print("findall:", all_matches)
# 5. finditer(): 모든 매칭 결과를 반복자(iterator)로 반환
print("finditer:")
for m in pattern.finditer(text):
print(" -", m.group(), "at", m.span())
# 6. sub(): 매칭된 부분을 다른 문자열로 치환
replaced = pattern.sub("fruit", text)
print("sub:", replaced)
# 7. split(): 패턴을 기준으로 문자열을 분할
split_text = pattern.split(text)
print("split:", split_text)
결과는 다음과 같음:
search: Apple
match: Apple
fullmatch: No full match
findall: ['Apple', 'apple', 'apple']
finditer:
- Apple at (0, 5)
- apple at (18, 23)
- apple at (42, 47)
sub: fruit pie and pinefruit are tasty. I like fruits.
split: ['', ' pie and pine', ' are tasty. I like ', 's.']
2. re.Match: return object
pattern이 대상 문자열에 matching 되는 경우,
반환되는 객체는re.Match클래스의 객체임.
매칭된 문자열의 정보들을 제공하는 다음의 methods를 가짐:
group(): 매칭된 문자열 반환.groups(): 캡처 그룹 반환.start(): 매칭 시작 위치.end(): 매칭 끝 위치.span(): 매칭 범위 (start, end)
이는 4번의 함수들에서 반환하는 객체에 해당함.
간단한 예제 코드는 다음과 같음:
import re
# 예시 문자열
text = "My phone number is 010-1234-5678."
# 패턴: 전화번호 형식, 세 부분을 그룹으로 나눔
pattern = re.compile(r"(\d{3})-(\d{4})-(\d{4})")
# search()로 매칭된 첫 결과 얻기
match = pattern.search(text)
if match:
print("group():", match.group()) # 전체 매칭된 문자열
print("groups():", match.groups()) # 캡처된 그룹 전체 튜플
print("group(1):", match.group(1)) # 첫 번째 그룹
print("group(2):", match.group(2)) # 두 번째 그룹
print("group(3):", match.group(3)) # 세 번째 그룹
print("start():", match.start()) # 전체 매칭 시작 위치
print("end():", match.end()) # 전체 매칭 끝 위치
print("span():", match.span()) # (start, end) 튜플
else:
print("No match found.")
결과는 다음과 같음:
group(): 010-1234-5678
groups(): ('010', '1234', '5678')
group(1): 010
group(2): 1234
group(3): 5678
start(): 19
end(): 32
span(): (19, 32)
3. re 모듈의 함수 기본 사용법.
re 모듈의 기능을 사용하는 방법은 일반적으로 다음과 같음.
# compile pattern으로 처리하는 경우.
compiledPattern = re.compile(rawPattern, flags=0)
compiledPattern.function(...)
# pattern을 그냥 raw string등으로 입력받는 경우.
# w/o compile
retv = re.function(rawPattern, ..., flags=0)
4. re 모듈이 제공하는 기본 함수들
4-1. match()
source의 string에서 시작부분이 pattern과 matching되는지를 체크하고,
- matching시 해당 부분에 대한 re.Match 객체로 반환하고,
- matching이 되는 문자열 부분이 없으면 None을 반환.
사용법은 다음과 같음.
match(
pattern: str|re.Pattern,
string:str,
flags:int=0
) -> Optional[re.Match]
- re.Pattern 을 사용하는 경우, flags는 무시됨.
사용가능한 flag는 다음과 같으며 bitwise or `|`를 사용해 조함 가능.
re.I:re.IGNORECASE, 대소문자 무시하고 매칭.re.M:re.MULTILINE, 다중라인 처리.`^`,`$`가 각 줄의 시작과 끝에 매칭되도록 처리됨.re.S:re.DOTALL,`.`가 개행문자(`\n`)를 포함하여 모든 문자에 매칭됨.re.ASCII: 유니코드 문자를 제외하고 ASCII 문자만 사용하여 매칭 처리.0: 기본모드 동작- 대소문자 구분,
`^`는 문자열의 시작,`$`는 문자열의 끝에만 매칭.`\w`,`\d`는 word와 digit인데 유니코드 단어의 문자들 및 유니코드 숫자 문자들을 포함하여 매칭: Python3는 unicode를 기본으로 지원함.- pattern은 공백이나 주석을 허용하지 않음
예제는 다음과 같음.
>>> mo = re.match(r"\d+", "067 Starts with a number")
>>> mo
<_sre.SRE_Match object; span=(0, 3), match='067'>
>>> mo.group()
'067'
>>> re.match(r"\d+", "Does not start with a number")
None
>>> if mo: # match returns an object; do this to see what matched
... print(mo.group())
...
067
re.fullmatch 의 경우는 문자열 전체가 패턴과 매칭되는지를 확인하고, 일치하는 경우만 re.Match객체를 반환하고 아니면 None임.
re.fullmathc(
pattern: str|re.Pattern,
string: str,
flags: int = 0
) -> Optional[re.Match]
- re.Pattern 을 사용하는 경우, flags는 무시됨.
4-2. search()
source의 string에서 pattern과 matching되는 부분이 있는지를 체크하고,
처음으로 matching된 부분에 대한 re.Match 객체를 반환하거나, 없으면 None을 반환.
사용법은 다음과 같음.
search(
pattern:str | re.Pattern,
string:str,
flags: int=0
) -> Optional[re.Match]
- re.Pattern 을 사용하는 경우, flags는 무시됨.
예제를 참고.
>>> mo = re.search(r"[a-z]+", "0010010 Has at least one 010 letter 0010010", re.I)
>>> mo
<_sre.SRE_Match object; span=(8, 11), match='Has'>
>>> # Case-sensitive version
>>> re.search(r"[a-z]+", "0010010 Has at least one 010 letter 0010010")
<_sre.SRE_Match object; span=(9, 11), match='as'>
re.Iflag를 사용하지 않은 경우,Has에서 소문자엔as부분이 처음으로 matching된 부분에 해당함.
다음과 같이 group등으로도 활용가능함.
>>> import re
>>> source = 'Young Frankenstein'
>>> m = re.search('Frank', source)
>>> if m:
... print(m.group())
...
Frank
4-3. findall()
source의 string에서 pattern과 matching되는 부분이 있는지를 체크하고,
모든 matching된 부분을 overlapping없는 문자열들의 list 객체로 만들어 반환.
단, 그룹명을 포함하도록 패턴이 지칭된 경우에는 tuple 들의 list 객체를 반환.
사용법은 다음과 같음.
findall(
pattern: str | re.Pattern,
string:str,
flags:int=0
) -> List[str] | List(Tuple[str, ...]]
- re.Pattern 을 사용하는 경우, flags는 무시됨.
예제는 다음과 같음.
>>> mo = re.findall(r"[a-z]+", "0010010 Has at least one 010 letter 0010010", re.I)
>>> mo
['Has', 'at', 'least', 'one', 'letter']
또 다른 예제.
>>> import re
>>> source = 'Young Frankenstein'
>>> m = re.findall('n', source)
>>> m # findall returns a list
['n', 'n', 'n', 'n']
>>> print('Found', len(m), 'matches')
Found 4 matches
finditer 의 경우, Iterator를 반환함.
re.finditer(
pattern: str|re.Pattern,
string: str,
flags: int=0
) -> Iterator[re.Match]
- re.Pattern 을 사용하는 경우, flags는 무시됨.
4-5. split()
source를 pattern에 해당하는 부분들로 나눈 list를 반환
(나누는 기준으로 사용된 pattern들은 output에 포함되지 않음.)
사용법은 다음과 같음.
split(
pattern: str | re.Pattern,
string: str,
maxsplit:int=0,
flags:int=0
) -> List[str]
maxsplit은 최대로 나눌 substring의 수임.- 0일 경우 최대한으로 나누어지게 되며 기본설정임.
- re.Pattern 을 사용하는 경우, flags는 무시됨.
예제는 다음과 같음.
>>> mo = re.split(r"\W", "Hello, world!")
>>> mo
['Hello', '', 'world', '']
>>> # Combine all adjacent non-letters
>>> mo = re.split(r"\W+", "Hello, world!")
['Hello', 'world', '']
다른 예제
>>> import re
>>> source = 'Young Frankenstein'
>>> m = re.split('n', source)
>>> m # split returns a list
['You', 'g Fra', 'ke', 'stei', '']
4-6. sub()
source에서 mathcing되는 부분들을 주어진 새 문자열로 바꾼 output을 반환.
추가적인 바꿀 새문자열 replacement가 argument로 주어짐.
sub(
pattern: str|re.Pattern,
repl: str | Callable[[re.Match, str],
string: str,
count:int=0,
flags:int=0
) -> str
- re.Pattern 을 사용하는 경우, flags는 무시됨.
치환한 횟수도 함께 반환하는 re.subn() 도 있음.
re.sub(
pattern: str|re.Pattern,
repl: str|Callable[[re.Match], str],
string: str,
count: int=0,
flags: int=0
) -> Tuple[str, int]
- 치환된 문자열과 치환횟수로 구성된 tuple 객체를 반환.
- re.Pattern 을 사용하는 경우, flags는 무시됨.
예제를 살펴볼 것.
>>> mo = re.sub(r"[a-z ]+", "[...]", "0010010 has at least one 010 letter 0010010")
>>> mo
'0010010[...]010[...]0010010'
또 다른 예제
>>> import re
>>> source = 'Young Frankenstein'
>>> m = re.sub('n', '?', source)
>>> m # sub returns a string
'You?g Fra?ke?stei?'
compile된 pattern을 사용하는 방식은 다음과 같음.
import re
# rawPattern = r'aaa'
rawPattern = r'\baaa\b' # 단어가 전체가 aaa인 경우만 해당함.
# compile pattern으로 처리하는 경우.
compiledPattern = re.compile(rawPattern, flags=0)
src = "aaa is an aaa. but aaabbb can be bbbaaa"
compiledPattern.sub("test",src)
결과는 다음과 같음.
test is an test. but aaabbb can be bbbaaa
5. match시 group에 이름을 지정하고 접근하기.
다음 예제를 참고
>>> source = '''I wish I may, I wish I might
... Have a dish of fish tonight.'''
>>> m = re.search(r'(?P<DISH>. dish\b).*(?P<FISH>\bfish)', source)
>>> m.group()
'a dish of fish'
>>> m.groups()
('a dish', 'fish')
>>> m.group('DISH')
'a dish'
>>> m.group('FISH')
'fish'
같이 보면 좋은 자료들
[Python] Regular Expression : 표현식 기초 및요약
Regular Expression : 정규표현식 요약 Regular Expression (re) 의 기본적인 operator는 다음과 같음.Basic operatorDescription.Any character except `\n` (newline)aThe character a itselfabThe string ab itselfx|yx or y\yEscapes a special char
ds31x.tistory.com
'Programming' 카테고리의 다른 글
| [Python] for statement (0) | 2023.07.30 |
|---|---|
| [PyQt6] QSizePolicy 설정. (0) | 2023.07.03 |
| [Python] str: Overloaded Operators (0) | 2023.07.02 |
| [Python] pip 란 (Package Management System) (0) | 2023.06.22 |
| [Python] Basic Methods of String (0) | 2023.06.21 |