Python 정규식 모듈 re(match, search, sub 등)를 사용하는 방법

사업

Python에서 정규식 처리를 수행하기 위해 표준 라이브러리의 re 모듈을 사용합니다. 정규식 패턴을 사용하여 문자열을 추출, 교체 및 분할할 수 있습니다.

이 섹션에서는 먼저 re 모듈의 기능과 방법에 대해 설명합니다.

  • 정규 표현식 패턴 컴파일:compile()
  • 일치 개체
  • 문자열의 시작 부분이 일치하는지 확인하고 다음을 추출합니다.match()
  • 시작 부분에 국한되지 않는 일치 항목을 확인하십시오.search()
  • 전체 문자열이 일치하는지 확인:fullmatch()
  • 일치하는 모든 부품 목록을 가져옵니다.findall()
  • 일치하는 모든 부분을 반복자로 가져옵니다.finditer()
  • 일치하는 부분을 교체하십시오.sub(),subn()
  • 정규식 패턴으로 문자열 분할:split()

그런 다음 re 모듈에서 사용할 수 있는 메타 문자(특수 문자)와 정규 표현식의 특수 시퀀스에 대해 설명합니다. 기본적으로는 표준 정규식 구문이지만 플래그(특히 re.ASCII) 설정에 주의하십시오.

  • Python의 정규 표현식 메타 문자, 특수 시퀀스 및 주의 사항
  • 플래그 설정
    • ASCII 문자로 제한:re.ASCII
    • 대소문자를 구분하지 않음:re.IGNORECASE
    • 각 줄의 시작과 끝을 일치시킵니다.re.MULTILINE
    • 여러 플래그 지정
  • 욕심 많은 경기와 욕심 없는 경기

정규 표현식 패턴 컴파일: compile()

re 모듈에서 정규식 처리를 수행하는 두 가지 방법이 있습니다.

기능으로 실행

첫 번째는 기능입니다.re.match(),re.sub()이러한 함수는 정규식 패턴을 사용하여 추출, 교체 및 기타 프로세스를 수행하는 데 사용할 수 있습니다.

함수에 대한 자세한 설명은 후술하겠지만, 모두 첫 번째 인자는 정규표현식 패턴의 문자열이고, 그 뒤에 처리할 문자열이 오는 식이다. 예를 들어, 대체를 수행하는 re.sub()에서 두 번째 인수는 대체 문자열이고 세 번째 인수는 처리할 문자열입니다.

import re

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

이 예에서 정규식 패턴의 [a-z]는 a에서 z까지의 모든 문자(즉, 소문자 알파벳)를 의미하고 +는 이전 패턴(이 경우 [a-z])을 한 번 이상 반복한다는 것을 의미합니다. [a-z]+는 하나 이상의 소문자 알파벳 문자를 반복하는 모든 문자열과 일치합니다.

. 메타 문자(특별한 의미의 문자)이며 백슬래시로 이스케이프해야 합니다.

정규식 패턴 문자열은 백슬래시를 많이 사용하기 때문에 예제와 같이 원시 문자열을 사용하는 것이 편리합니다.

정규식 패턴 개체의 메서드에서 실행

re 모듈에서 정규식을 처리하는 두 번째 방법은 정규식 패턴 개체 메서드입니다.

re.compile()을 사용하여 정규식 패턴 문자열을 컴파일하여 정규식 패턴 개체를 만들 수 있습니다.

p = re.compile(r'([a-z]+)@([a-z]+)\.com')

print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')

print(type(p))
# <class 're.Pattern'>

re.match(),re.sub()예를 들어, 정규식 객체의 match(),sub() 메서드로 이러한 함수와 동일한 프로세스를 실행할 수 있습니다.

m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

아래에서 설명하는 모든 re.xxx() 함수도 정규식 객체의 메서드로 제공됩니다.

동일한 패턴을 사용하는 프로세스를 반복하는 경우 re.compile()을 사용하여 정규식 개체를 생성하고 주변에 사용하는 것이 더 효율적입니다.

다음 샘플 코드에서는 편의상 컴파일하지 않고 함수를 사용하고 있지만, 동일한 패턴을 반복적으로 사용하고 싶다면 미리 컴파일하여 정규식 객체의 메소드로 실행하는 것을 권장합니다.

일치 개체

match(), search() 등은 일치 개체를 반환합니다.

s = 'aaa@xxx.com'

m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(m))
# <class 're.Match'>

일치하는 문자열과 위치는 일치 개체의 다음 메서드를 사용하여 가져옵니다.

  • 경기 위치 가져오기:start(),end(),span()
  • 일치하는 문자열을 가져옵니다.group()
  • 각 그룹에 대한 문자열을 가져옵니다.groups()
print(m.start())
# 0

print(m.end())
# 11

print(m.span())
# (0, 11)

print(m.group())
# aaa@xxx.com

정규식 패턴의 일부를 string형에 괄호()로 묶으면 해당 부분이 그룹으로 처리됩니다. 이 경우 groups()에서 각 그룹과 일치하는 부분의 문자열을 튜플로 얻을 수 있습니다.

m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.groups())
# ('aaa', 'xxx', 'com')

문자열의 시작 부분이 일치하는지 확인하고 추출: match()

match()는 문자열의 시작이 패턴과 일치하는 경우 일치 개체를 반환합니다.

위에서 언급했듯이 match 객체는 일치하는 부분 문자열을 추출하거나 단순히 일치하는지 확인하는 데 사용할 수 있습니다.

match()는 시작 부분만 확인합니다. 처음에 일치하는 문자열이 없으면 None을 반환합니다.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None

시작 부분에 국한되지 않는 일치 항목을 확인하고 다음을 추출합니다. search()

match()와 마찬가지로 일치하는 경우 일치 개체를 반환합니다.

일치하는 부분이 여러 개인 경우 첫 번째 일치하는 부분만 반환됩니다.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

일치하는 모든 부분을 얻으려면 아래 설명된 대로 findall() 또는 finditer()를 사용하십시오.

전체 문자열이 일치하는지 확인: fullmatch()

전체 문자열이 정규식 패턴과 일치하는지 확인하려면 fullmatch()를 사용합니다. 예를 들어 문자열이 이메일 주소로 유효한지 여부를 확인하는 데 유용합니다.

전체 문자열이 일치하면 일치 개체가 반환됩니다.

s = 'aaa@xxx.com'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

일치하지 않는 부분이 있는 경우(일치하는 부분만 있거나 전혀 일치하지 않는 경우) 없음이 반환됩니다.

s = '!!!aaa@xxx.com!!!'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None

fullmatch()는 Python 3.4에 추가되었습니다. 이전 버전에서 동일한 작업을 수행하려면 끝에 match() 및 일치하는 메타 문자 $를 사용하십시오. 전체 문자열이 처음부터 끝까지 일치하지 않으면 None을 반환합니다.

s = '!!!aaa@xxx.com!!!'

m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None

일치하는 모든 부분의 목록 가져오기: findall()

findall()은 일치하는 모든 하위 문자열의 목록을 반환합니다. 목록의 요소는 일치 개체가 아니라 문자열입니다.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']

일치하는 부분의 수는 목록의 요소 수를 반환하는 내장 함수 len()을 사용하여 확인할 수 있습니다.

print(len(result))
# 3

정규식 패턴에서 괄호()를 사용하여 그룹화하면 요소가 각 그룹의 문자열인 튜플 목록이 반환됩니다. 이것은 일치 객체의 groups()와 동일합니다.

result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]

그룹 괄호()는 중첩될 수 있으므로 전체 일치도 가져오려면 전체 일치 항목을 괄호()로 묶으면 됩니다.

result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]

일치하는 항목이 없으면 빈 튜플이 반환됩니다.

result = re.findall('[0-9]+', s)
print(result)
# []

일치하는 모든 부분을 반복자로 가져옵니다. finditer()

finditer()는 일치하는 모든 부분을 반복자로 반환합니다. 요소는 findall()과 같은 문자열이 아니라 일치 객체이므로 일치하는 부분의 위치(인덱스)를 얻을 수 있습니다.

반복자 자체는 내용을 얻기 위해 print()로 출력할 수 없습니다. 내장 함수 next()나 for문을 사용하면 내용을 하나씩 얻을 수 있다.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>

print(type(result))
# <class 'callable_iterator'>

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

list()를 사용하여 목록으로 변환할 수도 있습니다.

l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]

print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(l[0]))
# <class 're.Match'>

print(l[0].span())
# (0, 11)

일치하는 모든 부분의 위치를 ​​얻으려면 list()보다 목록 이해 표기법이 더 편리합니다.

print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]

반복자는 요소를 순서대로 꺼냅니다. 끝에 도달한 후 더 많은 요소를 추출하려고 하면 아무것도 남지 않습니다.

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

print(list(result))
# []

일치하는 부분 교체: sub(), subn()

sub()를 사용하여 일치하는 부분을 다른 문자열로 바꿀 수 있습니다. 대체된 문자열이 반환됩니다.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

print(type(result))
# <class 'str'>

괄호()로 그룹화할 때 일치하는 문자열을 대체된 문자열에서 사용할 수 있습니다.

기본적으로 다음이 지원됩니다. 원시 문자열이 아닌 일반 문자열의 경우 백슬래시를 이스케이프하려면 백슬래시 앞에 백슬래시를 나열해야 합니다.

\1첫 번째 괄호
\2두 번째 괄호
\3세 번째 괄호
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

?P<xxx>
정규식 패턴의 괄호 시작 부분에 이것을 써서 그룹의 이름을 지정하면 아래와 같이 숫자 대신 이름을 사용하여 지정할 수 있습니다.
\g<xxx>

result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

인수 count는 최대 교체 수를 지정합니다. 왼쪽의 카운트만 교체됩니다.

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net

subn()은 대체된 문자열의 튜플(sub()의 반환 값과 동일)과 대체된 부분의 수(패턴과 일치하는 수)를 반환합니다.

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)

인수를 지정하는 방법은 sub()와 동일합니다. 괄호로 묶은 부분을 사용하거나 인수 개수를 지정할 수 있습니다.

result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)

정규 표현식 패턴으로 문자열 분할: split()

split()은 패턴과 일치하는 부분에서 문자열을 분할하고 목록으로 반환합니다.

첫 번째 및 마지막 일치 항목에는 결과 목록의 시작과 끝에 빈 문자열이 포함됩니다.

s = '111aaa222bbb333'

result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']

result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']

maxsplit 인수는 최대 분할(조각) 수를 지정합니다. 왼쪽부터 카운트만 분할됩니다.

result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']

Python의 정규 표현식 메타 문자, 특수 시퀀스 및 주의 사항

Python 3 re 모듈에서 사용할 수 있는 주요 정규식 메타 문자(특수 문자) 및 특수 시퀀스는 다음과 같습니다.

메타 문자내용물
.개행 이외의 단일 문자(DOTALL 플래그가 있는 개행 포함)
^문자열의 시작(또한 MULTILINE 플래그가 있는 각 줄의 시작과 일치)
$문자열의 끝(MULTILINE 플래그가 있는 각 줄의 끝과도 일치)
*이전 패턴을 0회 이상 반복
+이전 패턴을 한 번 이상 반복합니다.
?이전 패턴을 0 또는 1회 반복합니다.
{m}이전 패턴을 m번 반복
{m, n}마지막 패턴입니다.m~n반복하다
[]문자 집합[]다음 문자 중 하나와 일치
|또는A|BA 또는 B 패턴과 일치
특별한 순서내용물
\d유니코드 십진수(ASCII 플래그에 의한 ASCII 숫자로 제한됨)
\D\d이것의 반대를 의미합니다.
\s유니코드 공백 문자(ASCII 플래그에 의해 ASCII 공백 문자로 제한됨)
\S\s이것의 반대를 의미합니다.
\w유니코드 단어 문자 및 밑줄(ASCII 영숫자 문자 및 ASCII 플래그에 의한 밑줄로 제한됨)
\W\w이것의 반대를 의미합니다.

이 표에 모두 나열되어 있는 것은 아닙니다. 전체 목록은 공식 문서를 참조하십시오.

또한 Python 2에서는 일부 의미가 다릅니다.

플래그 설정

위의 표와 같이 일부 메타 문자와 특수 시퀀스는 플래그에 따라 모드가 변경됩니다.

여기서는 주요 플래그만 다룹니다. 나머지는 공식 문서를 참조하십시오.

ASCII 문자로 제한: re.ASCII

\w이것은 또한 기본적으로 Python 3 문자열에 대해 2바이트 간지, 영숫자 문자 등과 일치합니다. 표준 정규식이 아니기 때문에 다음과 동일하지 않습니다.[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None

각 함수의 인수 플래그에 re.ASCII를 지정하거나 정규식 패턴 문자열의 시작 부분에 다음 인라인 플래그를 추가하면 ASCII 문자만 일치합니다(2바이트 일본어, 영숫자 문자 등은 일치하지 않습니다. .).
(?a)
이 경우 다음 두 가지는 동일합니다.
\w#ERROR![a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None

m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None

re.compile()로 컴파일할 때도 마찬가지입니다. 인수 플래그 또는 인라인 플래그를 사용하십시오.

p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

ASCII는 약식 re로도 사용할 수 있습니다. A. 둘 다 사용할 수 있습니다.

print(re.ASCII is re.A)
# True

\W의 반대인 \W도 re.ASCII 및 인라인 플래그의 영향을 받습니다.

m = re.match(r'\W+', '漢字ABC123')
print(m)
# None

m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

\w와 마찬가지로 다음 두 문자는 기본적으로 1바이트 문자와 2바이트 문자 모두와 일치하지만 re.ASCII 또는 인라인 플래그가 지정된 경우 단일 바이트 문자로 제한됩니다.

  • 숫자 일치\d
  • 공백과 일치\s
  • 숫자가 아닌 것과 일치\D
  • 공백이 아닌 모든 항목과 일치합니다.\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None

m = re.match(r'\s+', ' ')  # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>

m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None

대소문자를 구분하지 않음:re.IGNORECASE

기본적으로 대소문자를 구분합니다. 둘 다 일치시키려면 패턴에 대문자와 소문자를 모두 포함해야 합니다.

re.IGNORECASE이것이 지정되면 대소문자를 구분하지 않고 일치합니다. 표준 정규식의 i 플래그와 동일합니다.

m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

보다 작거나 같음을 사용할 수 있습니다.

  • 인라인 플래그(?i)
  • 약어re.I

각 줄의 시작과 끝을 일치시킵니다.re.MULTILINE

^이 정규식의 메타 문자는 문자열의 시작 부분과 일치합니다.

기본적으로 전체 문자열의 시작 부분만 일치하지만 다음은 각 줄의 시작 부분과도 일치합니다. 표준 정규식의 m 플래그와 동일합니다.
re.MULTILINE

s = '''aaa-xxx
bbb-yyy
ccc-zzz'''

print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz

result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']

result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']

result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']

$문자열의 끝과 일치합니다. 기본적으로 전체 문자열의 끝 부분만 일치합니다.
re.MULTILINE이것을 지정하면 각 줄의 끝과도 일치합니다.

result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']

result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']

보다 작거나 같음을 사용할 수 있습니다.

  • 인라인 플래그(?m)
  • 약어re.M

여러 플래그 지정

|동시에 여러 플래그를 활성화하려면 이것을 사용하십시오. 인라인 플래그의 경우 다음과 같이 각 문자 뒤에 문자가 와야 합니다.
(?am)

s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''

print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz

result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']

result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']

result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']

욕심 많은 경기와 욕심 없는 경기

이것은 파이썬만의 문제가 아니라 정규 표현식의 일반적인 문제이지만, 문제를 일으키기 쉬우므로 이에 대해 글을 쓰겠습니다.

기본적으로 다음은 가능한 가장 긴 문자열과 일치하는 욕심 많은 일치입니다.

  • *
  • +
  • ?
s = 'aaa@xxx.com, bbb@yyy.com'

m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>

print(m.group())
# aaa@xxx.com, bbb@yyy.com

NS ? 그 후에 가능한 한 가장 짧은 문자열과 일치하는 욕심이 없고 최소한의 일치가 됩니다.

  • *?
  • +?
  • ??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.group())
# aaa@xxx.com

기본 탐욕 일치는 예기치 않은 문자열과 일치할 수 있습니다.

Copied title and URL