在Ruby中分割句子的更好的正则表达式是什么?

4

我正在开发一个功能,用于计算一堆文本中单词出现的频率,并告知它们所在的句子,并按照每个单词的出现频率对结果进行排序。例如:

sample input and out put

目前我已经完成了以下内容:

File.open('sample_text.txt', 'r') do |f| # open a file named "sample_text.txt"

content = f.read # turn the content into a long string

# split the string by sentences
sentences = content.split(/\.|\?|\!/).each do |es|

  es.split(/\W|\s/).each do |w| 
     #split into individual words 
     #and for each word, find matched words in the content

  end

end
end

问题:

1. 是否有更好的正则表达式来分隔句子?现在使用split(/\.|\?|\!/)会将web 2.0视为两个句子web 20

2. 有人能给我一些提示,如何返回包含某个单词的句子数组吗?


2
如果使用了适当的格式,您应该检查标点符号后面是否有两个空格。这就是为什么在分隔句子的标点符号后应该使用双空格的原因之一,除了美观和一般做一个体面的人以外。继续使用双空格吧,它还要活很长时间。 - Sean Hill
4个回答

1
1. 想法如何?在句号(或者像问号或感叹号这样的标点符号)后面要求加一个空格,然后可选择地防止其前面出现某些常见的缩写词(例如"vs."、"Mr."、"Mrs."、"i.e."、"e.g."),并且可能要求后面有一个大写字母吗?
2. 给定一个句子字符串数组和一个将每个句子分割成单词数组的方法(这部分由您完成),您可以这样做:
sentences_for_word = Hash.new { |h, k| h[k] = [] } sentences.each do |sentence| words_for_sentence(sentence).each do |word| sentences_for_word[word] << sentence end end

  1. 但是如何将这些特殊单词添加到正则表达式中呢?
  2. 谢谢!=)
- vinc386
3
请查看斯坦福解析器。它有一个Ruby绑定和getSentencesFromString等方法。 - Art Shayderov

1

这里是一个完整的工作示例

require 'pp'
content = "Meet Mr. Jon. Jon is a computer programmer and lives in Connecticut. Jon is tall. Shouldn't take web 2.0 as two sentences. And this is a new sentence. "
words = {}
content.gsub!(/(Mr)\.|(Mrs)\./,"\\1{dot}").split(/\. |\? |\! /).each_with_index do |sentences, index|
  puts "\n#{index}: #{sentences}"
  sentences.split(/ +/).each do |word|
    word=word.gsub(/{dot}/,"\.").downcase
    puts word
    words[word]=words[word]||[0,[]]
    words[word][0]+=1
    words[word][1]<<index
  end
end
pp words

最后的pp给出

{"meet"=>[1, [0]],
 "mr."=>[1, [0]],
 "jon"=>[3, [0, 1, 2]],
 "is"=>[3, [1, 2, 4]],
 "a"=>[2, [1, 4]],
 "computer"=>[1, [1]],
 "programmer"=>[1, [1]],
 "and"=>[2, [1, 4]],
 "lives"=>[1, [1]],
 "in"=>[1, [1]],
 "connecticut"=>[1, [1]],
 "tall"=>[1, [2]],
 "shouldn't"=>[1, [3]],
 "take"=>[1, [3]],
 "web"=>[1, [3]],
 "2.0"=>[1, [3]],
 "as"=>[1, [3]],
 "two"=>[1, [3]],
 "sentences"=>[1, [3]],
 "this"=>[1, [4]],
 "new"=>[1, [4]],
 "sentence"=>[1, [4]]}

你可以根据最小长度过滤掉像"a"这样的单词,或将它们放在黑名单中。
很好奇你正在做什么,我正在为维基构建一个索引器,因为我无法在我的Windows/Ruby上使用Xapian。
问候。

0
使用单词边界匹配器:str.split(/ \ W + /)。它适用于大多数文本(尽管我猜测它将在'字符上分割)。

0

你可以通过添加正向先行断言来改进你的正则表达式

(?:\.|\?|\!)(?= [^a-z]|$)

在Regexr上这里查看

(?= [^a-z]|$)是一个正向预查,用于检查前面是否有一个空格后跟着一个非小写字母或字符串的结尾。这已经对匹配带来了很大的改进。

Phrogz提出的另一个建议(防止匹配常见缩写)无法在一个步骤中使用正则表达式实现,因为Ruby不支持后顾断言。

为了实现这个目标,需要更多的步骤。第一步是搜索这些缩写词并将它们替换为占位符(例如,将Mr.替换为Mr#DOT#),然后在点上分割后再次替换占位符。

仅供娱乐,与Ruby无关!后顾版本:

(?<!\be\.g|\bi\.e|\bvs|\bMr|\bMrs|\bDr)(?:\.|\?|\!)(?= |$)

在Regexr上这里查看它


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接