J'essaie de compter le nombre de fois qu'une chaîne apparaît dans une autre chaîne.
Je sais que vous pouvez compter le nombre de fois qu'une lettre apparaît dans une chaîne:
string = "aabbccddbb"
string.count('a')
=> 2
Mais si je recherche le nombre de fois où 'aa' apparaît dans cette chaîne, j'en reçois également deux.
string.count('aa')
=> 2
Je ne comprends pas ça. Je mets la valeur entre guillemets, donc je recherche le nombre de fois que la chaîne exacte apparaît, pas seulement les lettres.
Voici quelques façons de compter le nombre de fois qu'une sous-chaîne donnée apparaît dans une chaîne (la première étant ma préférence). Notez (comme confirmé par l'OP) la sous-chaîne 'aa'
apparaît deux fois dans la chaîne 'aaa'
, et donc cinq fois dans:
string="aaabbccaaaaddbb"
# 1
Utilisez String # scan avec un regex qui contient un lookahead positif qui recherche la sous-chaîne:
def count_em(string, substring)
string.scan(/(?=#{substring})/).count
end
count_em(string,"aa")
#=> 5
Remarque:
"aaabbccaaaaddbb".scan(/(?=aa)/)
#=> ["", "", "", "", ""]
Un lookbehind positif produit le même résultat:
"aaabbccaaaaddbb".scan(/(?<=aa)/)
#=> ["", "", "", "", ""]
Ainsi que, String#scan
peut être remplacé par String # gsub .
# 2
Convertissez en tableau, appliquez Enumerable # each_cons , puis rejoignez et comptez:
def count_em(string, substring)
string.each_char.each_cons(substring.size).map(&:join).count(substring)
end
count_em(string,"aa")
#=> 5
On a:
enum0 = "aaabbccaaaaddbb".each_char
#=> #<Enumerator: "aaabbccaaaaddbb":each_char>
Nous pouvons voir les éléments qui seront générés par cet énumérateur en le convertissant en un tableau:
enum0.to_a
#=> ["a", "a", "a", "b", "b", "c", "c", "a", "a", "a",
# "a", "d", "d", "b", "b"]
enum1 = enum0.each_cons("aa".size)
#=> #<Enumerator: #<Enumerator: "aaabbccaaaaddbb":each_char>:each_cons(2)>
Convertir enum1
à un tableau pour voir quelles valeurs l'énumérateur transmettra à map
:
enum1.to_a
#=> [["a", "a"], ["a", "a"], ["a", "b"], ["b", "b"], ["b", "c"],
# ["c", "c"], ["c", "a"], ["a", "a"], ["a", "a"], ["a", "a"],
# ["a", "d"], ["d", "d"], ["d", "b"], ["b", "b"]]
c = enum1.map(&:join)
#=> ["aa", "aa", "ab", "bb", "bc", "cc", "ca",
# "aa", "aa", "aa", "ad", "dd", "db", "bb"]
c.count("aa")
#=> 5
C'est parce que les count
comptent caractères , pas les instances de chaînes. Dans ce cas 'aa'
signifie la même chose que 'a'
, il est considéré comme un ensemble de caractères à compter.
Pour compter le nombre de fois que aa
apparaît dans la chaîne:
string = "aabbccddbb"
string.scan(/aa/).length
# => 1
string.scan(/bb/).length
# => 2
string.scan(/ff/).length
# => 0