鉴于输入:
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"]]
答案 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勾勒出的:
each_cons
处理该阵列的变体在代码中:
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"]