2014-09-19 21 views
22

Sto provando a contare il numero di volte che una stringa appare in un'altra stringa.Ruby: come contare il numero di volte che una stringa appare in un'altra stringa?

So che è possibile contare il numero di volte in cui una lettera appare in una stringa:

string = "aabbccddbb" 
string.count('a') 
=> 2 

Ma se la ricerca di quante volte 'AA' appare in questa stringa, ho anche ottenere due.

string.count('aa') 
=> 2 

non capisco questo. Inserisco il valore tra virgolette, quindi cerco il numero di volte in cui appare la stringa esatta, non solo le lettere.

+2

Si prega di chiarire (con una modifica): '' aa'' appare una o due volte nella stringa ''aaa''. –

+0

Probabilmente dovrebbe essere il doppio in questo caso.Posizioni 0 e 1 && Posizioni 1 e 2 – Johnson

+0

Certo, sei un poster eccellente. Ti ho premiato Cary Swoveland. – Johnson

risposta

26

Qui ci sono un paio di modi per contare il numero di volte una data sottostringa appare in una stringa (il primo è la mia preferenza). Nota (come confermato dalla OP) sottostringa 'aa' appare due volte nella stringa 'aaa', e quindi cinque volte a:

string="aaabbccaaaaddbb" 

# 1

Utilizzare String#scan con una regex che contiene un lookahead positivo cerca la stringa:

def count_em(string, substring) 
    string.scan(/(?=#{substring})/).count 
end 

count_em(string,"aa") 
#=> 5 

Nota:

"aaabbccaaaaddbb".scan(/(?=aa)/) 
    #=> ["", "", "", "", ""] 

Un lookbehind positiva produce lo stesso risultato:

"aaabbccaaaaddbb".scan(/(?<=aa)/) 
    #=> ["", "", "", "", ""] 

# 2

Converti in una matrice, applicare Enumerable#each_cons, quindi unire e contare:

def count_em(string, substring) 
    string.each_char.each_cons(substring.size).map(&:join).count(substring) 
end 

count_em(string,"aa") 
    #=> 5 

Abbiamo:

enum0 = "aaabbccaaaaddbb".each_char 
    #=> #<Enumerator: "aaabbccaaaaddbb":each_char> 

Possiamo vedere gli elementi che generati da questo enumeratore convertendolo in un array:

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)> 

Convertire enum1 di un array per vedere quali valori l'enumeratore passerà al 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 
15

È perché il count conta caratteri, non le istanze di stringhe. In questo caso 'aa' significa la stessa cosa di 'a', è considerato un insieme di caratteri da contare.

per contare il numero di volte aa appare nella stringa:

string = "aabbccddbb" 
string.scan(/aa/).length 
# => 1 
string.scan(/bb/).length 
# => 2 
string.scan(/ff/).length 
# => 0 
+0

Vedo, per trovare il conteggio delle stringhe effettive, si utilizza il metodo di scansione anziché il metodo di conteggio. Grazie. – Johnson

+1

Sì ['scan'] (http://www.ruby-doc.org/core-2.1.2/String.html#method-i-scan) prende un'espressione regolare come'/aa/'o anche una stringa come '" aa "' se preferisci e restituisce le partite. 'length' ti dice quante partite se non ti interessa quali sono le partite. – tadman

+0

È inoltre possibile utilizzare il conteggio o la dimensione anziché la lunghezza – Johnson

Problemi correlati