2013-03-20 16 views
7

Próbuję uzyskać zdania z ciągu znaków, który zawiera dany podciąg przy użyciu Pythona.Odnajdywanie otaczającego zdania znaku/słowa w ciągu znaków

Mam dostęp do napisu (streszczenie akademickie) i listę najważniejszych z indeksami początkowymi i końcowymi. Na przykład:

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

Mam pętli na każdym podświetleniem, lokalizowanie to początek indeksu w sposób abstrakcyjny (koniec naprawdę nie ma znaczenia, jak po prostu trzeba uzyskać lokalizację w zdaniu), a potem jakoś trzeba identyfikuj zdanie, w którym występuje ten indeks.

Potrafię tokenizować streszczenie w zdania przy użyciu nltk.tonenize.sent_tokenize, ale w ten sposób renderuję lokalizację indeksu bezużyteczną.

Jak mam rozwiązać ten problem? Przypuszczam, że regexes są opcją, ale tokenizer nltk wydaje się być tak fajnym sposobem robienia tego, że byłoby to wstydu nie skorzystać z niego .. Lub jakoś zresetować indeks początkowy przez znalezienie liczby znaków od poprzedniego pełnego zatrzymania/wykrzyknik/znak zapytania?

+0

to wygląda JSON. – squiguy

+0

Tak, manipuluję danymi z punktu końcowego API. – Elise

+0

Może to być kosztowne, ale można przejść przez zdania i przeliczyć indeksy zdań z długości, a następnie wyszukać ten indeks. – user1937198

Odpowiedz

6

Masz rację, tokenizer NLTK jest naprawdę tym, czego powinieneś używać w tej sytuacji, ponieważ jest wystarczająco solidny, aby obsłużyć rozgraniczenie głównie wszystkich zdań, w tym kończąc zdanie z "cytatem". Można zrobić coś takiego (paragraph z generatora):

początek,

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 = [] 

najbardziej intuicyjny sposób:

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

Ale za pomocą tej metody możemy rzeczywiście czym właściwie jest 3-krotnie zagnieżdżona pętla for. Dzieje się tak, ponieważ najpierw sprawdzamy każdy sentence, następnie każdy highlight, a następnie każdy podciąg w sentence dla highlight.

Możemy uzyskać lepszą wydajność, ponieważ wiemy, indeks początkowy dla każdego podświetlenia:

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) 

W obu przypadkach otrzymujemy:

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

To jest dokładnie to, czego szukałem, proste i łatwe do zrozumienia, dzięki! – Elise

1

Zakładam, że wszystkie zdania skończyć z jednym z tych trzech znaków: !?.

Co o zapętlenie nad listą najważniejszych, tworząc grupę regexp:

(?:list|of|your highlights) 

Następnie dopasowanie całe streszczenie przed ten regexp:

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

w ten sposób można dostać wyrok zawierający co najmniej jeden z najważniejszych w pierwszym subgrou p każdego meczu (RegExr).

0

Inną opcją (choć ciężko powiedzieć, w jaki sposób niezawodny byłoby ze zmiennie zdefiniowanego tekstu), byłoby podzielić tekst na listę zdań i test przed nimi:

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