Być może będziesz musiał nltk.download()najpierw uruchomić i pobrać modele ->punkt
Martin Thoma
2
Nie udaje się to w przypadkach z końcowymi cudzysłowami. Jeśli mamy zdanie, które kończy się jak „to”.
Fosa
1
Okej, przekonałeś mnie. Ale właśnie przetestowałem i nie wygląda na to, żeby mi się udało. Mój wkład jest, 'This fails on cases with ending quotation marks. If we have a sentence that ends like "this." This is another sentence.'a mój wynik ['This fails on cases with ending quotation marks.', 'If we have a sentence that ends like "this."', 'This is another sentence.']wydaje się być poprawny dla mnie.
szedjani
101
Ta funkcja może podzielić cały tekst Huckleberry Finn na zdania w około 0,1 sekundy i obsługuje wiele bardziej bolesnych skrajnych przypadków, które sprawiają, że analiza zdań jest nietrywialna, np. „ Pan John Johnson Jr. urodził się w USA, ale zdobył tytuł doktora. D. w Izraelu, zanim dołączył do Nike Inc. jako inżynier. Pracował również na craigslist.org jako analityk biznesowy ”.
# -*- coding: utf-8 -*-import re
alphabets="([A-Za-z])"
prefixes ="(Mr|St|Mrs|Ms|Dr)[.]"
suffixes ="(Inc|Ltd|Jr|Sr|Co)"
starters ="(Mr|Mrs|Ms|Dr|He\s|She\s|It\s|They\s|Their\s|Our\s|We\s|But\s|However\s|That\s|This\s|Wherever)"
acronyms ="([A-Z][.][A-Z][.](?:[A-Z][.])?)"
websites ="[.](com|net|org|io|gov)"def split_into_sentences(text):
text =" "+ text +" "
text = text.replace("\n"," ")
text = re.sub(prefixes,"\\1<prd>",text)
text = re.sub(websites,"<prd>\\1",text)if"Ph.D"in text: text = text.replace("Ph.D.","Ph<prd>D<prd>")
text = re.sub("\s"+ alphabets +"[.] "," \\1<prd> ",text)
text = re.sub(acronyms+" "+starters,"\\1<stop> \\2",text)
text = re.sub(alphabets +"[.]"+ alphabets +"[.]"+ alphabets +"[.]","\\1<prd>\\2<prd>\\3<prd>",text)
text = re.sub(alphabets +"[.]"+ alphabets +"[.]","\\1<prd>\\2<prd>",text)
text = re.sub(" "+suffixes+"[.] "+starters," \\1<stop> \\2",text)
text = re.sub(" "+suffixes+"[.]"," \\1<prd>",text)
text = re.sub(" "+ alphabets +"[.]"," \\1<prd>",text)if"”"in text: text = text.replace(".”","”.")if"\""in text: text = text.replace(".\"","\".")if"!"in text: text = text.replace("!\"","\"!")if"?"in text: text = text.replace("?\"","\"?")
text = text.replace(".",".<stop>")
text = text.replace("?","?<stop>")
text = text.replace("!","!<stop>")
text = text.replace("<prd>",".")
sentences = text.split("<stop>")
sentences = sentences[:-1]
sentences =[s.strip()for s in sentences]return sentences
To świetne rozwiązanie. Jednak dodałem do niego jeszcze dwa wiersze digits = "([0-9])" w deklaracji wyrażeń regularnych i text = re.sub (cyfry + "[.]" + Cyfry, "\\ 1 <prd> \ \ 2 ", tekst) w funkcji. Teraz nie dzieli linii w miejscach po przecinku, takich jak 5,5. Dziękuję za tę odpowiedź.
Ameya Kulkarni
1
Jak przeanalizowałeś cały Huckleberry Fin? Gdzie to jest w formacie tekstowym?
PascalVKooten
6
Świetne rozwiązanie. W funkcji dodałem if "np." In text: text = text.replace ("eg", "e <prd> g <prd>") if "ie" in text: text = text.replace ("ie" , „i <prd> e <prd>”) i całkowicie rozwiązało mój problem.
Sisay Chala
3
Świetne rozwiązanie z bardzo pomocnymi komentarzami! Wystarczy, aby uczynić go trochę bardziej wytrzymała jednak: prefixes = "(Mr|St|Mrs|Ms|Dr|Prof|Capt|Cpt|Lt|Mt)[.]", websites = "[.](com|net|org|io|gov|me|edu)", iif "..." in text: text = text.replace("...","<prd><prd><prd>")
Dascienz
1
Czy można sprawić, by ta funkcja traktowała zdania takie jak to jako jedno zdanie: Kiedy dziecko pyta matkę „Skąd się biorą dzieci?”, Co należy jej odpowiedzieć?
twhale
50
Zamiast używać wyrażenia regularnego do dzielenia tekstu na zdania, możesz również użyć biblioteki nltk.
>>>from nltk import tokenize>>> p ="Good morning Dr. Adams. The patient is waiting for you in room number 3.">>> tokenize.sent_tokenize(p)['Good morning Dr. Adams.','The patient is waiting for you in room number 3.']
Przestrzeń jest mega wielka. ale jeśli potrzebujesz tylko rozdzielić na zdania, przeniesienie tekstu do spacji zajmie zbyt dużo czasu, jeśli masz do czynienia z potokiem danych
Berlines
@Berlines Zgadzam się, ale nie mogłem znaleźć żadnej innej biblioteki, która wykonuje tę pracę tak czysto, jak spaCy. Ale jeśli masz jakieś sugestie, mogę spróbować.
Elf
Również dla użytkowników AWS Lambda Serverless, pliki danych wsparcia spacy mają wiele 100 MB (angielski duży to> 400 MB), więc nie możesz używać takich rzeczy po wyjęciu z pudełka, bardzo niestety (wielki fan Spacy tutaj)
Julian H.
9
Oto środek drogi, który nie polega na żadnych zewnętrznych bibliotekach. Używam funkcji rozumienia list, aby wykluczyć nakładanie się skrótów i terminatorów, a także aby wykluczyć nakładanie się między odmianami zakończeń, na przykład: „.” vs. '."'
abbreviations ={'dr.':'doctor','mr.':'mister','bro.':'brother','bro':'brother','mrs.':'mistress','ms.':'miss','jr.':'junior','sr.':'senior','i.e.':'for example','e.g.':'for example','vs.':'versus'}
terminators =['.','!','?']
wrappers =['"',"'",')',']','}']def find_sentences(paragraph):
end =True
sentences =[]while end >-1:
end = find_sentence_end(paragraph)if end >-1:
sentences.append(paragraph[end:].strip())
paragraph = paragraph[:end]
sentences.append(paragraph)
sentences.reverse()return sentencesdef find_sentence_end(paragraph):[possible_endings, contraction_locations]=[[],[]]
contractions = abbreviations.keys()
sentence_terminators = terminators +[terminator + wrapper for wrapper in wrappers for terminator in terminators]for sentence_terminator in sentence_terminators:
t_indices = list(find_all(paragraph, sentence_terminator))
possible_endings.extend(([]ifnot len(t_indices)else[[i, len(sentence_terminator)]for i in t_indices]))for contraction in contractions:
c_indices = list(find_all(paragraph, contraction))
contraction_locations.extend(([]ifnot len(c_indices)else[i + len(contraction)for i in c_indices]))
possible_endings =[pe for pe in possible_endings if pe[0]+ pe[1]notin contraction_locations]if len(paragraph)in[pe[0]+ pe[1]for pe in possible_endings]:
max_end_start = max([pe[0]for pe in possible_endings])
possible_endings =[pe for pe in possible_endings if pe[0]!= max_end_start]
possible_endings =[pe[0]+ pe[1]for pe in possible_endings if sum(pe)> len(paragraph)or(sum(pe)< len(paragraph)and paragraph[sum(pe)]==' ')]
end =(-1ifnot len(possible_endings)else max(possible_endings))return enddef find_all(a_str, sub):
start =0whileTrue:
start = a_str.find(sub, start)if start ==-1:returnyield start
start += len(sub)
W prostych przypadkach (gdzie zdania kończą się normalnie) powinno to działać:
import re
text =''.join(open('somefile.txt').readlines())
sentences = re.split(r' *[\.\?!][\'"\)\]]* *', text)
Wyrażenie regularne to *\. +, które dopasowuje kropkę otoczoną 0 lub więcej spacjami po lewej stronie i 1 lub więcej po prawej stronie (aby zapobiec liczeniu czegoś takiego jak kropka w re.split jako zmiana w zdaniu).
Oczywiście nie jest to najbardziej solidne rozwiązanie, ale w większości przypadków będzie dobrze. Jedynym przypadkiem, którego to nie obejmuje, są skróty (może przejrzyj listę zdań i sprawdź, czy każdy ciąg sentenceszaczyna się od dużej litery?)
Nie przychodzi Ci do głowy sytuacja w języku angielskim, w którym zdanie nie kończy się kropką? Wyobraź sobie, że! Moją odpowiedzią na to byłoby „pomyśl jeszcze raz”. (Widzicie, co tam zrobiłem?)
Ned Batchelder
@Ned wow, nie mogę uwierzyć, że byłem taki głupi. Muszę być pijany czy coś.
Rafe Kettler
Używam Pythona 2.7.2 na Win 7 x86, a wyrażenie regularne w powyższym kodzie daje mi ten błąd SyntaxError: EOL while scanning string literal:, wskazując na nawias zamykający (po text). Ponadto wyrażenie regularne, do którego odwołujesz się w tekście, nie istnieje w przykładowym kodzie.
Sabuncu
1
Wyrażenie regularne nie jest całkowicie poprawne, tak jak powinnor' *[\.\?!][\'"\)\]]* +'
fsociety
Może to spowodować wiele problemów, a także podzielić zdanie na mniejsze fragmenty. Rozważmy przypadek, w którym mamy „Zapłaciłem 3,5 USD za te lody”, a kawałki to „Zapłaciłem 3 USD” i „5 za te lody”. użyj domyślnego zdania nltk. tokenizer jest bezpieczniejszy!
Reihan_amn
6
Możesz również użyć funkcji tokenizacji zdań w NLTK:
from nltk.tokenize import sent_tokenize
sentence ="As the most quoted English writer Shakespeare has more than his share of famous quotes. Some Shakespare famous quotes are known for their beauty, some for their everyday truths and some for their wisdom. We often talk about Shakespeare’s quotes as things the wise Bard is saying to us but, we should remember that some of his wisest words are spoken by his biggest fools. For example, both ‘neither a borrower nor a lender be,’ and ‘to thine own self be true’ are from the foolish, garrulous and quite disreputable Polonius in Hamlet."
sent_tokenize(sentence)
Cześć! Możesz stworzyć nowy tokenizer dla języka rosyjskiego (i kilku innych języków), korzystając z tej funkcji:
def russianTokenizer(text):
result = text
result = result.replace('.',' . ')
result = result.replace(' . . . ',' ... ')
result = result.replace(',',' , ')
result = result.replace(':',' : ')
result = result.replace(';',' ; ')
result = result.replace('!',' ! ')
result = result.replace('?',' ? ')
result = result.replace('\"',' \" ')
result = result.replace('\'',' \' ')
result = result.replace('(',' ( ')
result = result.replace(')',' ) ')
result = result.replace(' ',' ')
result = result.replace(' ',' ')
result = result.replace(' ',' ')
result = result.replace(' ',' ')
result = result.strip()
result = result.split(' ')return result
a potem nazwij to w ten sposób:
text ='вы выполняете поиск, используя Google SSL;'
tokens = russianTokenizer(text)
Bez wątpienia NLTK jest najbardziej odpowiedni do tego celu. Ale rozpoczęcie pracy z NLTK jest dość bolesne (ale po zainstalowaniu - po prostu czerpiesz korzyści)
# split up a paragraph into sentences# using regular expressionsdef splitParagraphIntoSentences(paragraph):''' break a paragraph into sentences
and return a list '''import re
# to split by multile characters# regular expressions are easiest (and fastest)
sentenceEnders = re.compile('[.!?]')
sentenceList = sentenceEnders.split(paragraph)return sentenceList
if __name__ =='__main__':
p ="""This is a sentence. This is an excited sentence! And do you think this is a question?"""
sentences = splitParagraphIntoSentences(p)for s in sentences:print s.strip()#output:# This is a sentence# This is an excited sentence# And do you think this is a question
Tak, ale to tak łatwo zawodzi, mówiąc: „Pan Smith wie, że to zdanie”.
thomas
0
Musiałem przeczytać pliki z napisami i podzielić je na zdania. Po wstępnym przetworzeniu (takim jak usunięcie informacji o czasie itp. Z plików .srt) zmienna fullFile zawierała pełny tekst pliku z napisami. Poniższy, prymitywny sposób zgrabnie podzielił je na zdania. Zapewne miałem szczęście, że zdania zawsze kończyły się (poprawnie) spacją. Spróbuj najpierw tego, a jeśli ma jakieś wyjątki, dodaj więcej kontroli i sald.
# Very approximate way to split the text into sentences - Break after ? . and !
fullFile = re.sub("(\!|\?|\.) ","\\1<BRK>",fullFile)
sentences = fullFile.split("<BRK>");
sentFile = open("./sentences.out","w+");for line in sentences:
sentFile.write (line);
sentFile.write ("\n");
sentFile.close;
O! dobrze. Teraz zdaję sobie sprawę, że ponieważ moja treść była hiszpańska, nie miałem problemów z radzeniem sobie z „Mr.
Pracowałem nad podobnym zadaniem i natrafiłem na to zapytanie, klikając kilka linków i pracując nad kilkoma ćwiczeniami dla nltk, poniższy kod działał dla mnie jak magia.
from nltk.tokenize import sent_tokenize
text ="Hello everyone. Welcome to GeeksforGeeks. You are studying NLP article"
sent_tokenize(text)
wynik:
['Hello everyone.','Welcome to GeeksforGeeks.','You are studying NLP article']
Odpowiedzi:
Natural Language Toolkit ( nltk.org ) ma to, czego potrzebujesz. Ten post grupowy wskazuje, że to robi:
(Nie próbowałem tego!)
źródło
nltk .tokenize.punkt.PunktSentenceTokenizer
.nltk.download()
najpierw uruchomić i pobrać modele ->punkt
'This fails on cases with ending quotation marks. If we have a sentence that ends like "this." This is another sentence.'
a mój wynik['This fails on cases with ending quotation marks.', 'If we have a sentence that ends like "this."', 'This is another sentence.']
wydaje się być poprawny dla mnie.Ta funkcja może podzielić cały tekst Huckleberry Finn na zdania w około 0,1 sekundy i obsługuje wiele bardziej bolesnych skrajnych przypadków, które sprawiają, że analiza zdań jest nietrywialna, np. „ Pan John Johnson Jr. urodził się w USA, ale zdobył tytuł doktora. D. w Izraelu, zanim dołączył do Nike Inc. jako inżynier. Pracował również na craigslist.org jako analityk biznesowy ”.
źródło
prefixes = "(Mr|St|Mrs|Ms|Dr|Prof|Capt|Cpt|Lt|Mt)[.]"
,websites = "[.](com|net|org|io|gov|me|edu)"
, iif "..." in text: text = text.replace("...","<prd><prd><prd>")
Zamiast używać wyrażenia regularnego do dzielenia tekstu na zdania, możesz również użyć biblioteki nltk.
ref: https://stackoverflow.com/a/9474645/2877052
źródło
for sentence in tokenize.sent_tokenize(text): print(sentence)
Możesz spróbować użyć Spacy zamiast regex. Używam go i spełnia swoje zadanie.
źródło
Oto środek drogi, który nie polega na żadnych zewnętrznych bibliotekach. Używam funkcji rozumienia list, aby wykluczyć nakładanie się skrótów i terminatorów, a także aby wykluczyć nakładanie się między odmianami zakończeń, na przykład: „.” vs. '."'
Użyłem funkcji find_all Karla z tego wpisu: Znajdź wszystkie wystąpienia podciągu w Pythonie
źródło
...
i?!
.W prostych przypadkach (gdzie zdania kończą się normalnie) powinno to działać:
Wyrażenie regularne to
*\. +
, które dopasowuje kropkę otoczoną 0 lub więcej spacjami po lewej stronie i 1 lub więcej po prawej stronie (aby zapobiec liczeniu czegoś takiego jak kropka w re.split jako zmiana w zdaniu).Oczywiście nie jest to najbardziej solidne rozwiązanie, ale w większości przypadków będzie dobrze. Jedynym przypadkiem, którego to nie obejmuje, są skróty (może przejrzyj listę zdań i sprawdź, czy każdy ciąg
sentences
zaczyna się od dużej litery?)źródło
SyntaxError: EOL while scanning string literal
:, wskazując na nawias zamykający (potext
). Ponadto wyrażenie regularne, do którego odwołujesz się w tekście, nie istnieje w przykładowym kodzie.r' *[\.\?!][\'"\)\]]* +'
Możesz również użyć funkcji tokenizacji zdań w NLTK:
źródło
@Artyom,
Cześć! Możesz stworzyć nowy tokenizer dla języka rosyjskiego (i kilku innych języków), korzystając z tej funkcji:
a potem nazwij to w ten sposób:
Powodzenia, Marilena.
źródło
Bez wątpienia NLTK jest najbardziej odpowiedni do tego celu. Ale rozpoczęcie pracy z NLTK jest dość bolesne (ale po zainstalowaniu - po prostu czerpiesz korzyści)
Oto prosty kod ponownie oparty na http://pythonicprose.blogspot.com/2009/09/python-split-paragraph-into-sentences.html
źródło
Musiałem przeczytać pliki z napisami i podzielić je na zdania. Po wstępnym przetworzeniu (takim jak usunięcie informacji o czasie itp. Z plików .srt) zmienna fullFile zawierała pełny tekst pliku z napisami. Poniższy, prymitywny sposób zgrabnie podzielił je na zdania. Zapewne miałem szczęście, że zdania zawsze kończyły się (poprawnie) spacją. Spróbuj najpierw tego, a jeśli ma jakieś wyjątki, dodaj więcej kontroli i sald.
O! dobrze. Teraz zdaję sobie sprawę, że ponieważ moja treść była hiszpańska, nie miałem problemów z radzeniem sobie z „Mr.
źródło
mam nadzieję, że to pomoże ci w tekście łacińskim, chińskim i arabskim
źródło
wynik:
Źródło: https://www.geeksforgeeks.org/nlp-how-tokenizing-text-sentence-words-works/
źródło