扫描连续单词组

时间:2012-05-26 02:50:19

标签: ruby

鉴于输入:

str = "foo bar jim jam. jar jee joon."

我需要用空格分隔的所有2和3字短语的输出:

[ "foo bar", "bar jim", "jim jam", "jar jee", "jee joon",
  "foo bar jim", "bar jim jam", "jar jee joon" ]

特别注意由于时期的原因,上面缺少“果酱罐”,“吉姆果酱罐”和“果酱罐头”。

我无法使用str.scan(/\w+/).each_cons(2).map{ |a| a.join(' ') },因为其中包含"jam jar"

扫描/\w+ \w+/会产生["foo bar", "jim jam", "jar jee"],特别是缺少“bar jim”和“jee joon”,并突出显示问题。

真实世界的应用程序是为搜索引擎生成基于短语的索引。我想找到所有真正连续的单词作为短语,不包括带分隔符的标点符号。

修改:似乎可以通过以下方式在regex / scan中执行此操作:

"a b c d".scan(/(?=([abc] [abc]) )[abc]/)
#=> [["a b"], ["b c"]]

4 个答案:

答案 0 :(得分:1)

str = "foo bar jim jam. jar jee joon."
arr = str.split(' ').each_cons(2).map do |a|
  a.join(' ') if a.join(' ').match(/\w+ \w+/)
end
p arr.compact
#=> ["foo bar", "bar jim", "jim jam.", "jar jee", "jee joon."]
编辑:看来你已经改变了你的问题,也要求提供3个单词的短语。 ಠ_ಠ

答案 1 :(得分:1)

我相信这可以胜任,虽然它假设唯一的标点符号是句号形式:

str.split(".").map do |s|
  pairs_and_triples = []
  s.split.each_cons(2){ |*words| pairs_and_triples << words.join(" ") }
  s.split.each_cons(3){ |*words| pairs_and_triples << words.join(" ")}
  pairs_and_triples
end.flatten

编辑或稍微减少重复:

str.split(".").map do |s|
  [2,3].map do |i|
    s.split.each_cons(i).map{ |*words| words.join(" ") }
  end.flatten
end.flatten

答案 2 :(得分:0)

我最终得到的强大而有效的解决方案是@muistooshort提出的并由@ChrisRice勾勒出的:

  1. 分割句子边界
  2. 扫描单词(忽略无趣的标点符号,如逗号)
  3. 使用each_cons处理该阵列的变体
  4. 在代码中:

    max_words_per_phrase = 5
    str = "foo bar, jim jam. jar: jee joon."
    
    phrases = str.split(/[.!?]+/).flat_map do |sentence|
      words = sentence.scan(/\w+/)
      2.upto(max_words_per_phrase).flat_map do |i|
        words.each_cons(i).map{ |a| a.join(' ') }
      end
    end
    
    p phrases
    #=> ["foo bar", "bar jim", "jim jam", "foo bar jim", "bar jim jam",
    #=>  "foo bar jim jam", "jar jee", "jee joon", "jar jee joon"]
    

答案 3 :(得分:0)

删除标点后:

str = "foo bar jim jam jar jee joon"

正如您在问题中所建议的那样,可以使用积极的前瞻:

r2 = /(\w+)(?=(\s+\w+))/
r3 = /(\w+)(?=(\s+\w+)(\s+\w+))/
str.scan(r2).concat(str.scan(r3)).map(&:join)
  #=> ["foo bar", "bar jim", "jim jam", "jam jar", "jar jee", "jee joon",
  #    "foo bar jim", "bar jim jam", "jim jam jar", "jam jar jee", "jar jee joon"]