webentwicklung-frage-antwort-db.com.de

Benennen Sie Namen, Dialoge und Aktionen aus dem Transkript mithilfe von Regex ab

Bei einem Zeichenfolgendialogfeld (siehe unten) muss ich den Satz finden, der jedem Benutzer entspricht. 

text = 'CHRIS: Hello, how are you...
PETER: Great, you? PAM: He is resting.
[PAM SHOWS THE COUCH]
[PETER IS NODDING HIS HEAD]
CHRIS: Are you ok?'

Für den obigen Dialog möchte ich Tupel mit drei Elementen zurückgeben mit: 

1) Name der Person

2) der Satz in Kleinbuchstaben und 

3) Die Sätze in Klammern

Sowas in der Art: 

('CHRIS', 'Hallo, wie geht es dir ...', keine)

('PETER', 'Großartig, du?', Keine)

('PAM', 'Er ruht sich aus', 'PAM ZEIGT DIE COUCH. PETER IS NODDING SEIN KOPF')

('CHRIS', 'Geht es dir gut?', Keine)

usw 

Ich versuche, Regex zu verwenden, um das oben genannte zu erreichen. Bisher konnte ich die Namen der Benutzer mit den unten stehenden Informationen abrufen. Ich bemühe mich, den Satz zwischen zwei Nutzern zu identifizieren. 

actors = re.findall(r'\w+(?=\s*:[^/])',text)

Jede Hilfe wird sehr geschätzt. 

4
pbou

Sie können dies mit re.findall tun:

>>> re.findall(r'\b(\S+):([^:\[\]]+?)\n?(\[[^:]+?\]\n?)?(?=\b\S+:|$)', text)
[('CHRIS', ' Hello, how are you...', ''),
 ('PETER', ' Great, you? ', ''),
 ('PAM',
  ' He is resting.',
  '[PAM SHOWS THE COUCH]\n[PETER IS NODDING HIS HEAD]\n'),
 ('CHRIS', ' Are you ok?', '')]

Sie müssen herausfinden, wie Sie die eckigen Klammern selbst entfernen können. Dies ist jedoch nicht mit Regex möglich, während Sie dennoch versuchen, alles zu finden.

Regex-Aufschlüsselung  

\b              # Word boundary
(\S+)           # First capture group, string of characters not having a space
:               # Colon
(               # Second capture group
    [^          # Match anything that is not...
        :       #     a colon
        \[\]    #     or square braces
    ]+?         # Non-greedy match
)
\n?             # Optional newline
(               # Third capture group
    \[          # Literal opening brace
    [^:]+?      # Similar to above - exclude colon from match
    \] 
    \n?         # Optional newlines
)?              # Third capture group is optional
(?=             # Lookahead for... 
    \b          #     a Word boundary, followed by  
    \S+         #     one or more non-space chars, and
    :           #     a colon
    |           # Or,
    $           # EOL
)
15
coldspeed

Regex ist eine Möglichkeit, dieses Problem anzugehen, Sie können jedoch auch daran denken, jedes Token in Ihrem Text zu durchlaufen und eine gewisse Logik zum Erstellen von Gruppen anzuwenden. 

Zum Beispiel könnten wir zuerst Gruppen von Namen und Text finden:

from itertools import groupby

def isName(Word):
    # Names end with ':'
    return Word.endswith(":")

text_split = [
    " ".join(list(g)).rstrip(":") 
    for i, g in groupby(text.replace("]", "] ").split(), isName)
]
print(text_split)
#['CHRIS',
# 'Hello, how are you...',
# 'PETER',
# 'Great, you?',
# 'PAM',
# 'He is resting. [PAM SHOWS THE COUCH] [PETER IS NODDING HIS HEAD]',
# 'CHRIS',
# 'Are you ok?']

Als nächstes können Sie Paare von aufeinander folgenden Elementen in text_split in Tupeln sammeln:

print([(text_split[i*2], text_split[i*2+1]) for i in range(len(text_split)//2)])
#[('CHRIS', 'Hello, how are you...'),
# ('PETER', 'Great, you?'),
# ('PAM', 'He is resting. [PAM SHOWS THE COUCH] [PETER IS NODDING HIS HEAD]'),
# ('CHRIS', 'Are you ok?')]

Wir sind fast am gewünschten Ausgang. Wir müssen uns nur mit dem Text in den eckigen Klammern befassen. Sie können dafür eine einfache Funktion schreiben. (Reguläre Ausdrücke sind zwar eine Option, aber ich vermeide es absichtlich in dieser Antwort.)

Hier ist etwas schnelles, das ich mir ausgedacht habe:

def isClosingBracket(Word):
    return Word.endswith("]")

def processWords(words):
    if "[" not in words:
        return [words, None]
    else:
        return [
            " ".join(g).replace("]", ".") 
            for i, g in groupby(map(str.strip, words.split("[")), isClosingBracket)
        ]

print(
    [(text_split[i*2], *processWords(text_split[i*2+1])) for i in range(len(text_split)//2)]
)
#[('CHRIS', 'Hello, how are you...', None),
# ('PETER', 'Great, you?', None),
# ('PAM', 'He is resting.', 'PAM SHOWS THE COUCH. PETER IS NODDING HIS HEAD.'),
# ('CHRIS', 'Are you ok?', None)]

Beachten Sie, dass die Verwendung von * zum Entpacken des Ergebnisses von processWords in Tuple ausschließlich eine Python-3-Funktion ist.

1
pault