2016-09-23 64 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 
相關問題