Python-Extraktmuster stimmt überein


128

Python 2.7.1 Ich versuche, den regulären Python-Ausdruck zu verwenden, um Wörter innerhalb eines Musters zu extrahieren

Ich habe eine Zeichenfolge, die so aussieht

someline abc
someother line
name my_user_name is valid
some more lines

Ich möchte das Wort "my_user_name" extrahieren. Ich mache so etwas

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>

Wie extrahiere ich jetzt meinen_Benutzernamen?

Antworten:


158

Sie müssen aus Regex erfassen. searchWenn das Muster gefunden wurde, rufen Sie die Zeichenfolge mit ab group(index). Vorausgesetzt, es werden gültige Prüfungen durchgeführt:

>>> 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.
'my_user_name'

25
Bist du sicher, dass das nicht group(0)für das erste Spiel ist?
— Sharshofski

33
Ein bisschen spät, aber sowohl ja als auch nein. group(0)Gibt den übereinstimmenden Text zurück, nicht die erste Erfassungsgruppe. Der Codekommentar ist korrekt, während Sie Capture-Gruppen und Übereinstimmungen zu verwirren scheinen. group(1)Gibt die erste Erfassungsgruppe zurück.
— Andrewgu

1
Ich bekommeNameError: name '_' is not defined
— Ian G

Ihre zweite Zeile sollte ich lesen _ = p.search(s). Ich sehe, dass erwähnt wird, dass das Ergebnis auf gesetzt wird, _aber der Code spiegelt dies nicht wider. Ich habe zu _ = p.search(s)dieser zweiten Zeile gewechselt und es funktioniert.
— Ian G

2
@IanG Es tut mir leid, ich werde meine Antwort aktualisieren. Übrigens, mit einer Standard-Python-REPL wird das letzte Ergebnis in einer speziellen Variablen namens gespeichert _. Es ist nirgendwo anders gültig.
— UltraInstinct

57

Sie können passende Gruppen verwenden:

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

z.B

>>> 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']

Hier verwende ich re.findalleher als re.searchalle Instanzen von zu bekommen my_user_name. Mit re.searchmüssen Sie die Daten aus der Gruppe für das Übereinstimmungsobjekt abrufen:

>>> 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'

Wie in den Kommentaren erwähnt, möchten Sie Ihren Regex möglicherweise nicht gierig machen:

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

um nur das Zeug zwischen 'name 'und dem nächsten aufzunehmen ' is valid'(anstatt zuzulassen, dass Ihr Regex andere ' is valid'in Ihrer Gruppe aufnimmt .


2
Es ist möglich, dass eine nicht gierige Übereinstimmung erforderlich ist ... (es sei denn, ein Benutzername kann aus mehreren Wörtern bestehen ...)
— Jon Clements

@ JonClements - Du meinst (.*?)? Ja, das ist möglich, aber nicht notwendig, es sei denn, wir verwendenre.DOTALL
— mgilson

Ja - wird re.findall('name (.*) is valid', 'name jon clements is valid is valid is valid')wahrscheinlich nicht die gewünschten Ergebnisse liefern ...
— Jon Clements

Dies funktioniert nicht für Python 2.7.1? Es druckt nur ein Musterobjekt?
— Kannan Ekanath

@CalmStorm - Welcher Teil funktioniert nicht (ich habe auf python2.7.3 getestet)? Der Teil, den ich benutze, .groupist genau der gleiche wie die Antwort, die Sie akzeptiert haben ...
— mgilson

16

Sie könnten so etwas verwenden:

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

Vielleicht ist das etwas kürzer und leichter zu verstehen:

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

Sie möchten eine Erfassungsgruppe .

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

Sie können Gruppen (mit '('und gekennzeichnet ')') verwenden, um Teile der Zeichenfolge zu erfassen. Die group()Methode des Übereinstimmungsobjekts gibt Ihnen dann den Inhalt der Gruppe:

>>> 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'

In Python 3.6+ können Sie auch in ein Übereinstimmungsobjekt indizieren, anstatt Folgendes zu verwenden group():

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

6

Hier ist eine Möglichkeit, dies ohne Verwendung von Gruppen zu tun (Python 3.6 oder höher):

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

1
Dies befasst sich mit Python Regex, jedoch nicht mit der spezifischen Frage von OP.
— Aleister Tanek Javas Mraz

Außerdem fügt dies den vorhandenen Antworten, die die Indizierungssyntax 3.6+ erwähnen, im Grunde nichts Neues hinzu.
— Eugene Yarmash

3

Sie können auch eine Erfassungsgruppe verwenden (?P<user>pattern)und wie ein Wörterbuch auf die Gruppe zugreifen 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

Es scheint, als ob Sie tatsächlich versuchen, einen Namen zu extrahieren, indem Sie einfach eine Übereinstimmung finden. In diesem Fall ist es hilfreich, Span-Indizes für Ihre Übereinstimmung zu haben, und ich würde die Verwendung empfehlen re.finditer. Als Verknüpfung wissen Sie, dass der nameTeil Ihres regulären Ausdrucks Länge 5 und is validLänge 9 ist, sodass Sie den passenden Text in Scheiben schneiden können, um den Namen zu extrahieren.

Hinweis - In Ihrem Beispiel sieht es so aus, als wäre ses eine Zeichenfolge mit Zeilenumbrüchen.

## 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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.