考虑到Mr. and Dr.和U.S.A等案例,您如何处理段落或大量文本并将其分解为句子(最好使用Ruby)? (假设你只是将句子放入数组数组中)
更新: 我想到的一个可能的解决方案是使用词性标注器(POST)和分类器来确定句子的结尾:
从琼斯先生那里获取数据时,他走出意大利避暑别墅的阳台,感受到了温暖的阳光。他很高兴活着。
CLASSIFIER 先生/ PERSON Jones / PERSON感觉/ O / O暖/ O太阳/ O开/ O他/ O面/ O / O他/ O步/ O出/ O到/ O / O阳台/ O / O他/ O夏天/ O home / O in / O意大利/ LOCATION ./O他/ O是/ O快乐/ O to / O be / O alive / O ./O
POST Mr.NNP Jones / NNP感觉/ VBD / DT暖/ JJ太阳/ NN on / IN他/ PRP $ face / NN as / IN他/ PRP步进/ VBD输出/ RP到/在/ DT阳台/ NN of /他/ PRP $ summer / NN home / NN in / IN Italy./NNP他/ PRP是/ VBD快乐/ JJ到/ TO是/ VB alive./IN
我们可以假设,由于意大利是一个地点,这段时间是句子的有效结束吗?自从“先生”结束没有其他词性,我们可以假设这不是一个有效的句末期吗?这是我问题的最佳答案吗?
思想?
答案 0 :(得分:13)
尝试查看Ruby wrapper around the Stanford Parser。它有一个getSentencesFromString()函数。
答案 1 :(得分:8)
为了说清楚,没有简单的解决方案。这是NLP研究的主题quick Google search显示。
然而,似乎有一些开源项目处理NLP支持句子检测,我找到了以下基于Java的工具集:
<强> openNLP 强>
附加评论:判断句子开始和结束位置的问题在sentence boundary disambiguation中也称为natural language processing(SBD)。
答案 2 :(得分:5)
查看NLTK(自然语言工具包)中的Python句子分割器:
它基于以下论文:
Kiss,Tibor和Strunk,Jan(2006):Unsupervised Multilingual Sentence Boundary Detection。 计算语言学 32:485-525。
本文的方法非常有趣。它们将句子分裂的问题减少到确定单词与跟随标点符号相关联的强度的问题。缩写后的句点重载是大多数模糊句点的原因,因此如果您能够识别缩写,则可以很有可能识别句子边界。
我已经非正式地测试了这个工具,它似乎可以为各种(人类)语言提供良好的结果。
将它移植到Ruby将是非常重要的,但它可能会给你一些想法。
答案 3 :(得分:5)
看起来这个红宝石宝石可能会成功。
答案 4 :(得分:4)
如果你真正关心的话,这是一个难题。您会发现NLP解析器包可能提供此功能。如果你想要更快的东西,你需要最终用一个训练的令牌窗口的概率函数来复制一些功能(你可能想要将换行计算为一个令牌,因为我可能会丢弃一段时间这是段落的结尾。)
编辑:如果您可以使用Java,我推荐使用Stanford解析器。我没有其他语言的推荐,但我非常有兴趣听听那些开源的东西。
答案 5 :(得分:2)
不幸的是,我不是一个红宝石的家伙,但也许perl中的一个例子会让你朝着正确的方向前进。使用不匹配的外观来结束标点符号然后在一个不落后的特殊情况下跟随任意数量的空格,然后查看大写字母。我确信这不完美,但我希望它指出你正确的方向。不知道你怎么知道美国是否真的在句子的末尾......
#!/usr/bin/perl
$string = "Mr. Thompson is from the U.S.A. and is 75 years old. Dr. Bob is a dentist. This is a string that contains several sentances. For example this is one. Followed by another. Can it deal with a question? It sure can!";
my @sentances = split(/(?:(?<=\.|\!|\?)(?<!Mr\.|Dr\.)(?<!U\.S\.A\.)\s+(?=[A-Z]))/, $string);
for (@sentances) {
print $_."\n";
}
答案 6 :(得分:1)
也许尝试将其拆分一段时间后跟一个空格后跟一个大写字母?我不确定如何找到大写字母,但那将是我开始看的模式。
修改: Finding uppercase letters with Ruby.
另一个编辑:
检查不以大写字母开头的单词后面的句子结尾标点符号。
答案 7 :(得分:1)
Manning博士的答案是最合适的,如果你正在考虑JAVA(以及Ruby也很难;))。它在这里 -
有一个句子分割器: edu.stanford.nlp.process.DocumentPreprocessor 。尝试命令:java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt
oneTokenizedSentencePerLine.txt。 (这是通过一个(好但是 启发式)FSM,所以它很快;你是 没有运行概率解析器。)
但是如果我们修改命令java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt TO java edu.stanford.nlp.process.DocumentPreprocessor -file /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt 。它将正常工作,因为您需要指定将哪种文件呈现为输入。 所以文件文件的文件,HTML的-html等
答案 8 :(得分:1)
我没试过,但如果英语是你唯一关心的语言,我建议给Lingua::EN::Readability看看。
Lingua :: EN :: Readability是一个Ruby模块,用于计算英文文本的统计信息。它可以提供单词,句子和音节的计数。它还可以计算几种可读性度量,例如雾指数和Flesch-Kincaid级别。该软件包包括Lingua :: EN :: Sentence模块,它将英文文本分解为缩写的句子,以及Lingua :: EN :: Syllable,可以猜出书面英文单词中的音节数。如果发音字典可用,它可以查找字典中的音节数量以获得更高的准确度
您想要的位在sentence.rb
中,如下所示:
module Lingua
module EN
# The module Lingua::EN::Sentence takes English text, and attempts to split it
# up into sentences, respecting abbreviations.
module Sentence
EOS = "\001" # temporary end of sentence marker
Titles = [ 'jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'rep',
'rev', 'gov', 'atty', 'supt', 'det', 'rev', 'col','gen', 'lt',
'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj' ]
Entities = [ 'dept', 'univ', 'uni', 'assn', 'bros', 'inc', 'ltd', 'co',
'corp', 'plc' ]
Months = [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul',
'aug', 'sep', 'oct', 'nov', 'dec', 'sept' ]
Days = [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ]
Misc = [ 'vs', 'etc', 'no', 'esp', 'cf' ]
Streets = [ 'ave', 'bld', 'blvd', 'cl', 'ct', 'cres', 'dr', 'rd', 'st' ]
@@abbreviations = Titles + Entities + Months + Days + Streets + Misc
# Split the passed text into individual sentences, trim these and return
# as an array. A sentence is marked by one of the punctuation marks ".", "?"
# or "!" followed by whitespace. Sequences of full stops (such as an
# ellipsis marker "..." and stops after a known abbreviation are ignored.
def Sentence.sentences(text)
text = text.dup
# initial split after punctuation - have to preserve trailing whitespace
# for the ellipsis correction next
# would be nicer to use look-behind and look-ahead assertions to skip
# ellipsis marks, but Ruby doesn't support look-behind
text.gsub!( /([\.?!](?:\"|\'|\)|\]|\})?)(\s+)/ ) { $1 << EOS << $2 }
# correct ellipsis marks and rows of stops
text.gsub!( /(\.\.\.*)#{EOS}/ ) { $1 }
# correct abbreviations
# TODO - precompile this regex?
text.gsub!( /(#{@@abbreviations.join("|")})\.#{EOS}/i ) { $1 << '.' }
# split on EOS marker, strip gets rid of trailing whitespace
text.split(EOS).map { | sentence | sentence.strip }
end
# add a list of abbreviations to the list that's used to detect false
# sentence ends. Return the current list of abbreviations in use.
def Sentence.abbreviation(*abbreviations)
@@abbreviations += abbreviations
@@abbreviations
end
end
end
end
答案 9 :(得分:1)
同意接受的答案,使用斯坦福大学核心NLP是一个没脑子的人。
但是,在2016年,incompatibilities与stanford核心nlp的更高版本(我遇到Stanford Parser问题)有一些Stanford Core NLP v3.5接口。
以下是我使用Ruby与Stanford Core NLP接口解析文本到句子的方法:
安装Stanford CoreNLP gem - 它仍然保持并且正常工作,找到最近工作的NLP红宝石宝石一直很困难:
gem install stanford-core-nlp
然后按照readme for Using the latest version of the Stanford CoreNLP:
使用最新版本的Stanford CoreNLP(版本3.5.0) 2014年3月31日)需要一些额外的手动步骤:
将提取的存档的内容放在/ bin /文件夹中 stanford-core-nlp gem(例如[...] / gems / stanford-core-nlp-0.x / bin /) 或者在通过设置配置的目录位置内 StanfordCoreNLP.jar_path。
- 从full Stanford Tagger version 3.5.0下载http://nlp.stanford.edu/。
- 制作名为&#39; taggers&#39;的目录在stanford-core-nlp gem的/ bin /文件夹中(例如 [...] / gems / stanford-core-nlp-0.x / bin /)或目录内 通过设置StanfordCoreNLP.jar_path进行配置。
- 放置内容 标记器目录中提取的存档。
- 从the bridge.jar file下载https://github.com/louismullie/stanford-core-nlp。
- 将下载的bridger.jar文件放在。的/ bin /文件夹中 stanford-core-nlp gem(例如 [...] / gems / stanford-core-nlp-0.x / bin / taggers /)或目录内 通过设置StanfordCoreNLP.jar_path配置。
然后将ruby代码分割成句子:
require "stanford-core-nlp"
#I downloaded the StanfordCoreNLP to a custom path:
StanfordCoreNLP.jar_path = "/home/josh/stanford-corenlp-full-2014-10-31/"
StanfordCoreNLP.use :english
StanfordCoreNLP.model_files = {}
StanfordCoreNLP.default_jars = [
'joda-time.jar',
'xom.jar',
'stanford-corenlp-3.5.0.jar',
'stanford-corenlp-3.5.0-models.jar',
'jollyday.jar',
'bridge.jar'
]
pipeline = StanfordCoreNLP.load(:tokenize, :ssplit)
text = 'Mr. Josh Weir is writing some code. ' +
'I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.'
text = StanfordCoreNLP::Annotation.new(text)
pipeline.annotate(text)
text.get(:sentences).each{|s| puts "sentence: " + s.to_s}
#output:
#sentence: Mr. Josh Weir is writing some code.
#sentence: I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.
答案 10 :(得分:0)
我不是Ruby人,而是分裂的RegEx
^(Mr|Mrs|Ms|Mme|Sta|Sr|Sra|Dr|U\.S\.A)[\.\!\?\"] [A-Z]
一旦你有了段落(在\ r \ n上分开),将是我最好的选择。这假定你的句子是正确的。
显然这是一个相当难看的RegEx。如何在句子之间强制两个空格
答案 11 :(得分:0)
打破一段时间,然后是一个空格和一个大写字母,不会像“布朗先生”这样的标题。
这些时期会让事情变得困难,但要处理的一个简单案例就是感叹号和问号。但是,有些情况会导致这种情况无效。即Yahoo!的公司名称。
答案 12 :(得分:0)
显然paragraph.split('.')
不会削减它
#split
将采用正则表达式作为答案,因此您可以尝试使用零宽度lookbehind来检查以大写字母开头的单词。当然这会分散在专有名词上,所以你可能不得不求助于像/(Mr\.|Mrs\.|U\.S\.A ...)
这样的正则表达式,除非你以编程方式构建正则表达式,否则它会非常难看。
答案 13 :(得分:0)
我认为这并不总是可以解决,但你可以根据“。”(一个句号后面跟着空格)分开,并验证句号之前的单词不在像Mr,Dr这样的单词列表中。等
但是,当然,你的列表可能会省略一些单词,在这种情况下你会得到不好的结果。
答案 14 :(得分:0)