Python 추출 패턴 일치


129

Python 2.7.1 패턴 내에서 단어를 추출하기 위해 Python 정규식을 사용하려고합니다.

다음과 같은 문자열이 있습니다.

someline abc
someother line
name my_user_name is valid
some more lines

"my_user_name"이라는 단어를 추출하고 싶습니다. 나는 뭔가를한다

import re
s = #that big string
p = re.compile("name .* is valid", re.flags)
p.match(s) #this gives me <_sre.SRE_Match object at 0x026B6838>

지금 my_user_name을 어떻게 추출합니까?

답변:


159

정규식에서 캡처해야합니다. search패턴에 대해 찾으면을 사용하여 문자열을 검색합니다 group(index). 유효한 검사가 수행되었다고 가정합니다.

>>> p = re.compile("name (.*) is valid")
>>> result = p.search(s)
>>> result
<_sre.SRE_Match object at 0x10555e738>
>>> result.group(1)     # group(1) will return the 1st capture.
                        # group(0) will returned the entire matched text.
'my_user_name'

26
group(0)첫 경기 가 아니라고 확신 하십니까?
sharshofski

33
다소 늦었지만 예와 아니오 모두. group(0)첫 번째 캡처 그룹이 아니라 일치하는 텍스트를 반환합니다. 코드 주석은 정확하지만 캡처 그룹 및 일치를 혼동하는 것 같습니다. group(1)첫 번째 캡처 그룹을 반환합니다.
andrewgu

1
나는 얻는다NameError: name '_' is not defined
Ian G

두 번째 줄은 읽어야한다고 생각합니다 _ = p.search(s). 결과 설정에 대해 언급 _했지만 코드에는이를 반영하지 않습니다. _ = p.search(s)두 번째 줄로 변경 하면 작동합니다.
Ian G

2
@IanG 죄송합니다. 답변을 업데이트하겠습니다. BTW, 표준 python REPL을 사용하면 마지막 결과가라는 특수 변수에 저장됩니다 _. 다른 곳에서는 유효하지 않습니다.
UltraInstinct

57

일치하는 그룹을 사용할 수 있습니다.

p = re.compile('name (.*) is valid')

예 :

>>> import re
>>> p = re.compile('name (.*) is valid')
>>> s = """
... someline abc
... someother line
... name my_user_name is valid
... some more lines"""
>>> p.findall(s)
['my_user_name']

여기서는 모든 인스턴스를 가져 오는 re.findall대신 . 를 사용 하여 일치 개체의 그룹에서 데이터를 가져와야합니다.re.searchmy_user_namere.search

>>> p.search(s)   #gives a match object or None if no match is found
<_sre.SRE_Match object at 0xf5c60>
>>> p.search(s).group() #entire string that matched
'name my_user_name is valid'
>>> p.search(s).group(1) #first group that match in the string that matched
'my_user_name'

주석에서 언급했듯이 정규식을 탐욕스럽지 않게 만들고 싶을 수 있습니다.

p = re.compile('name (.*?) is valid')

정규식이 그룹의 다른 항목을 선택하도록 허용하지 않고 'name '다음 사이의 항목 만 선택합니다 .' is valid'' is valid'


2
탐욕스럽지 않은 일치가 필요할 수 있습니다 ... (사용자 이름이 여러 단어가 될 수없는 경우 ...)
Jon Clements

@JonClements-그러니까 (.*?)? OP 우리가 사용하지 않는 그래, 즉, 비록 필요하지 가능re.DOTALL
mgilson

예- re.findall('name (.*) is valid', 'name jon clements is valid is valid is valid')아마도 원하는 결과를 얻지 못할 것입니다 ...
Jon Clements

이것은 Python 2.7.1에서 작동하지 않습니까? 패턴 객체 만 인쇄합니까?
Kannan Ekanath 2013 년

@CalmStorm-어떤 부분이 작동하지 않습니까 (python2.7.3에서 테스트했습니다)? 내가 사용이 부분 .group정확히 허용 대답과 동일합니다 ...
mgilson

16

다음과 같이 사용할 수 있습니다.

import re
s = #that big string
# the parenthesis create a group with what was matched
# and '\w' matches only alphanumeric charactes
p = re.compile("name +(\w+) +is valid", re.flags)
# use search(), so the match doesn't have to happen 
# at the beginning of "big string"
m = p.search(s)
# search() returns a Match object with information about what was matched
if m:
    name = m.group(1)
else:
    raise Exception('name not found')

10

아마도 조금 더 짧고 이해하기 쉽습니다.

import re
text = '... someline abc... someother line... name my_user_name is valid.. some more lines'
>>> re.search('name (.*) is valid', text).group(1)
'my_user_name'

9

캡처 그룹을 원합니다 .

p = re.compile("name (.*) is valid", re.flags) # parentheses for capture groups
print p.match(s).groups() # This gives you a tuple of your matches.

9

그룹 ( '('및로 ')'표시됨)을 사용하여 문자열의 일부를 캡처 할 수 있습니다 . group()그런 다음 일치 개체의 메서드가 그룹의 콘텐츠를 제공합니다.

>>> import re
>>> s = 'name my_user_name is valid'
>>> match = re.search('name (.*) is valid', s)
>>> match.group(0)  # the entire match
'name my_user_name is valid'
>>> match.group(1)  # the first parenthesized subgroup
'my_user_name'

Python 3.6 이상에서는 다음 을 사용하는 대신 일치 객체로 인덱싱 할 수도 있습니다 group().

>>> match[0]  # the entire match 
'name my_user_name is valid'
>>> match[1]  # the first parenthesized subgroup
'my_user_name'

6

다음은 그룹을 사용하지 않고 수행하는 방법입니다 (Python 3.6 이상).

>>> re.search('2\d\d\d[01]\d[0-3]\d', 'report_20191207.xml')[0]
'20191207'

1
이것은 Python Regex를 다루지 만 OP의 특정 질문은 다루지 않습니다.
Aleister Tanek Javas Mraz

게다가 이것은 기본적으로 3.6+ 인덱싱 구문을 언급하는 기존 답변에 새로운 것을 추가하지 않습니다.
Eugene Yarmash

3

캡처 그룹을 사용 (?P<user>pattern)하고 사전처럼 그룹에 액세스 할 수도 있습니다 match['user'].

string = '''someline abc\n
            someother line\n
            name my_user_name is valid\n
            some more lines\n'''

pattern = r'name (?P<user>.*) is valid'
matches = re.search(pattern, str(string), re.DOTALL)
print(matches['user'])

# my_user_name

1

실제로 이름을 추출하려는 것 같습니다. 이 경우 일치하는 스팬 인덱스를 사용하는 것이 도움이되며 다음을 사용하는 것이 좋습니다.re.finditer . 지름길로 name정규식 의 일부가 길이 5이고is valid 길이가 9 있으므로 일치하는 텍스트를 슬라이스하여 이름을 추출 할 수 있습니다.

참고-귀하의 예에서는 s줄 바꿈이있는 문자열 처럼 보이 므로 아래에서 가정합니다.

## covert s to list of strings separated by line:
s2 = s.splitlines()

## find matches by line: 
for i, j in enumerate(s2):
    matches = re.finditer("name (.*) is valid", j)
    ## ignore lines without a match
    if matches:
        ## loop through match group elements
        for k in matches:
            ## get text
            match_txt = k.group(0)
            ## get line span
            match_span = k.span(0)
            ## extract username
            my_user_name = match_txt[5:-9]
            ## compare with original text
            print(f'Extracted Username: {my_user_name} - found on line {i}')
            print('Match Text:', match_txt)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.