2013-03-20 17 views
7

Ich versuche, Sätze von einer Zeichenkette zu erhalten, die eine gegebene Teilzeichenkette mit Python enthalten.Den umgebenden Satz eines Zeichens/Wortes in einer Zeichenkette finden

Ich habe Zugriff auf die Zeichenfolge (eine akademische Zusammenfassung) und eine Liste von Highlights mit Start- und Ende-Indizes. Zum Beispiel:

{ 
    abstract: "...long abstract here..." 
    highlights: [ 
    { 
     concept: 'a word', 
     start: 1, 
     end: 10 
    } 
    { 
     concept: 'cancer', 
     start: 123, 
     end: 135 
    } 
    ] 
} 

ich über jedes Highlight am Looping, Ortung ist es Index in der Zusammenfassung (das Ende ist nicht wirklich wichtig, wie ich brauche nur einen Ort zu bekommen innerhalb eines Satzes) beginnen und dann müssen irgendwie Identifizieren Sie den Satz, in dem der Index auftritt.

Ich bin in der Lage, die Zusammenfassung in Sätze mit nltk.tonenize.sent_tokenize zu tokenisieren, aber dadurch mache ich die Indexposition unbrauchbar.

Wie soll ich dieses Problem lösen? Ich denke, Regexes sind eine Option, aber der Tokenizer nltk scheint so eine nette Methode zu sein, dass es schade wäre, ihn nicht zu benutzen. Oder den Startindex irgendwie zurücksetzen, indem er die Anzahl der Zeichen seit dem letzten Punkt findet. Ausrufezeichen/Fragezeichen?

+0

Diese wie JSON aussieht. – squiguy

+0

Ja, ich manipuliere Daten von einem API-Endpunkt. – Elise

+0

Es könnte teuer sein, aber Sie könnten durch die Sätze gehen und die Indizes der Sätze von der Länge neu berechnen, dann suchen Sie nach diesem Index – user1937198

Antwort

6

Sie haben Recht, der NLTK Tokenizer ist wirklich, was Sie in dieser Situation verwenden sollten, da es robust genug ist, um die meisten Sätze zu begrenzen, einschließlich der Beendigung eines Satzes mit einem "Zitat". Sie können so etwas wie dieses (paragraph von einem Zufallsgenerator) tun:

Beginnen Sie mit,

from nltk.tokenize import sent_tokenize 

paragraph = "How does chickens harden over the acceptance? Chickens comprises coffee. Chickens crushes a popular vet next to the eater. Will chickens sweep beneath a project? Coffee funds chickens. Chickens abides against an ineffective drill." 
highlights = ["vet","funds"] 
sentencesWithHighlights = [] 

intuitive Art und Weise:

for sentence in sent_tokenize(paragraph): 
    for highlight in highlights: 
     if highlight in sentence: 
      sentencesWithHighlights.append(sentence) 
      break 

Aber mit dieser Methode, die wir tatsächlich haben was ist effektiv eine 3x verschachtelte for Schleife. Dies liegt daran, dass wir zunächst jede sentence, dann jede highlight, dann jede Untersequenz in der sentence für die highlight überprüfen.

können wir eine bessere Leistung, da wir den Startindex für jedes Highlight kennen:

highlightIndices = [100,169] 
subtractFromIndex = 0 
for sentence in sent_tokenize(paragraph): 
    for index in highlightIndices: 
     if 0 < index - subtractFromIndex < len(sentence): 
      sentencesWithHighlights.append(sentence) 
      break 
    subtractFromIndex += len(sentence) 

In beiden Fällen erhalten wir:

sentencesWithHighlights = ['Chickens crushes a popular vet next to the eater.', 'Coffee funds chickens.'] 
+1

Das ist genau das, was ich gesucht habe, einfach und leicht zu verstehen, danke! – Elise

1

Ich gehe davon aus, dass alle Sätze mit einem dieser drei Zeichen enden: !?.

Was über die Liste der Highlights über Looping, die Schaffung eines regexp Gruppe:

(?:list|of|your highlights) 

dann Ihre ganze abstrakte passende gegen diese regexp:

/(?:[\.!\?]|^)\s*([^\.!\?]*(?:list|of|your highlights)[^\.!\?]*?)(?=\s*[\.!\?])/ig 

diese Weise können Sie den Satz bekommen würde mindestens einen Ihrer Höhepunkte im ersten subgrou enthalten p jedes Spiels (RegExr).

0

Eine weitere Option (obwohl es hart ist, zuverlässig zu sagen, wie es mit variabel definiert Text wäre), wäre es, den Text in eine Liste von Sätzen und Test gegen sie zu spalten:

re.split('(?<=\?|!|\.)\s{0,2}(?=[A-Z]|$)', text) 
Verwandte Themen