2016-09-23 19 views
2

如何检查字符串中出现短语的次数?如何计算一个字符串元素在ruby中另一个字符串中的出现?

例如,让我们说这句话是donut

str1 = "I love donuts!" 
#=> returns 1 because "donuts" is found once. 
str2 = "Squirrels do love nuts" 
#=> also returns 1 because of 'do' and 'nuts' make up donut 
str3 = "donuts do stun me" 
#=> returns 2 because 'donuts' and 'do stun' has all elements to make 'donuts' 

我检查建议使用包括this SO,但如果是为了阐明它才会起作用。

我想出了这个,但它不会停止拼写所有元素"donuts"拼写。即"I love donuts" #=> ["o", "d", "o", "n", "u", "t", "s"]

def word(arr) 
    acceptable_word = "donuts".chars 
    arr.chars.select { |name| acceptable_word.include? name.downcase } 
end 

如何检查一个给定的字符串中如何许多发生在那里?没有边缘情况。输入将始终为String,不可为零。如果它包含donut的元素,则不应将其计为1次;它需要包含,并不是必须的。

+2

http://stackoverflow.com/questions/25938430/ruby-count-the-number-of-times-a-string-appears-in-another-string – Zepplock

+0

的可能重复这个问题* *不是**以上的重复,因为这里''眩晕''匹配''甜甜圈'',例如未请求子串匹配。 – mudasobwa

+0

不重复。虽然不同,我在我的帖子上指出这另一个SO:http://stackoverflow.com/questions/8258517/how-to-check-whether-a-string-contains-a-substring-in-ruby其中“排序“字符串无关紧要。也许“秩序”不是一个好的描述。对困惑感到抱歉!正如@mudasobwa所说,“甜甜圈”和“眩晕”都应该返回匹配。 – Iggy

回答

3

代码

def count_em(str, target) 
    target.chars.uniq.map { |c| str.count(c)/target.count(c) }.min 
end 

实例

count_em "I love donuts!", "donuts"      #=> 1 
count_em "Squirrels do love nuts", "donuts"    #=> 1 
count_em "donuts do stun me", "donuts"     #=> 2 
count_em "donuts and nuts sound too delicious", "donuts" #=> 3 
count_em "cats have nine lives", "donuts"    #=> 0 
count_em "feeding force scout", "coffee"     #=> 1 
count_em "feeding or scout", "coffee"     #=> 0 

str = ("free mocha".chars*4).shuffle.join 
    # => "hhrefemcfeaheomeccrmcre eef oa ofrmoaha " 
count_em str, "free mocha" 
    #=> 4 

说明

对于

str = "feeding force scout" 
target = "coffee" 

a = target.chars 
    #=> ["c", "o", "f", "f", "e", "e"] 
b = a.uniq 
    #=> ["c", "o", "f", "e"] 
c = b.map { |c| str.count(c)/target.count(c) } 
    #=> [2, 2, 1, 1] 
c.min 
    #=> 1 

在计算c,考虑传递给块和分配给该块变量cb第一个元素。

c = "c" 

则该块计算是

d = str.count(c) 
    #=> 2 
e = target.count(c) 
    #=> 1 
d/e 
    #=> 2 

这表明str包含足够"c"的以匹配 “咖啡” 的两倍。

其余的计算获得c是相似的。

补遗

如果str匹配字符target字符必须在相同的顺序那些target,可以使用下面的正则表达式。

target = "coffee" 

r = /#{ target.chars.join(".*?") }/i 
    #=> /c.*?o.*?f.*?f.*?e.*?e/i 

matches = "xcorr fzefe yecaof tfe erg eeffoc".scan(r) 
    #=> ["corr fzefe ye", "caof tfe e"] 
matches.size 
    #=> 2 

"feeding force scout".scan(r).size 
    #=> 0 

正则表达式中的问题是使搜索非贪婪所必需的。

+0

这是令人惊讶的紧凑和工作的短语,如“甜甜圈”与每个字母的单个实例,但会打破像“咖啡”的字母加倍。 “免费摩卡咖啡”应该与此相匹配吗? – tadman

+0

好点,@tadman。我修正了这一点。 –

3

的解决方案是或多或少简单(map(&:dup)用于有避免输入突变):

pattern = 'donuts' 
[str1, str2, str3].map(&:dup).map do |s| 
    loop.with_index do |_, i| 
    break i unless pattern.chars.all? { |c| s.sub!(c, '') } 
    end 
end 
#⇒ [1, 1, 2] 
+0

您的解决方案总是令人难以置信 – Aleksey

+0

谢谢,卡里,更新。 – mudasobwa

1

这里有两种变体的方法,一种是字母必须按顺序出现,另一种是顺序不相关。在这两种情况下,每封信的频率都受到尊重,所以“咖啡”必须与两个'f'和两个'e'字母匹配,“免费摩卡咖啡”不足以匹配,缺少第二个“f”。

def sorted_string(string) 
    string.split('').sort.join 
end 

def phrase_regexp_sequence(phrase) 
    Regexp.new(
    phrase.downcase.split('').join('.*') 
) 
end 

def phrase_regexp_unordered(phrase) 
    Regexp.new(
    phrase.downcase.gsub(/\W/, '').split('').sort.chunk_while(&:==).map do |bit| 
     "#{bit[0]}{#{bit.length}}" 
    end.join('.*') 
) 
end 

def contains_unordered(phrase, string) 
    !!phrase_regexp_unordered(phrase).match(sorted_string(string.downcase)) 
end 

def contains_sequence(phrase, string) 
    !!phrase_regexp_sequence(phrase).match(string.downcase) 
end 

strings = [ 
    "I love donuts!", 
    "Squirrels do love nuts", 
    "donuts do stun me", 
    "no stunned matches", 
] 

phrase = 'donut' 

strings.each do |string| 
    puts '%-30s %s %s' % [ 
    string, 
    contains_unordered(phrase, string), 
    contains_sequence(phrase, string) 
    ] 
end 

# => I love donuts!     true true 
# => Squirrels do love nuts   true true 
# => donuts do stun me    true true 
# => no stunned matches    true false 
相关问题