Ruby: Hoe tel je het aantal keren dat een string in een andere string voorkomt?

Ik probeer het aantal keren te tellen dat een tekenreeks in een andere tekenreeks voorkomt.

Ik weet dat je het aantal keren kunt tellen dat een letter in een string voorkomt:

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

Maar als ik zoek naar hoe vaak ‘aa’ in deze tekenreeks voorkomt, krijg ik er ook twee.

string.count('aa')
=> 2

Ik begrijp dit niet. Ik plaats de waarde tussen aanhalingstekens, dus ik zoek naar het aantal keren dat de exacte tekenreeks voorkomt, niet alleen naar de letters.


Antwoord 1, autoriteit 100%

Hier zijn een aantal manieren om het aantal keren te tellen dat een bepaalde subtekenreeks in een tekenreeks voorkomt (de eerste is mijn voorkeur). Let op (zoals bevestigd door de OP) de substring 'aa'verschijnt twee keer in de string 'aaa', en dus vijf keer in:

str = "aaabbccaaaaddbab"

#1

Gebruik String#scanmet een regex die een positieve vooruitblik bevat die zoekt naar de substring:

def count_em(str, substr)
  str.scan(/(?=#{substr})/).count
end
count_em(str,"aa")
  #=> 5
count_em(str,"ab")
  #=> 2

Opmerking:

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

Een positieve blik geeft hetzelfde resultaat:

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

Ook String#scankan worden vervangen door de vorm van String#gsubdie één argument nodig heeft (hier dezelfde reguliere expressie) en geen blok, en een enumerator retourneert. Die vorm van gsubis ongebruikelijk in die zin dat het niets te maken heeft met karaktervervanging; het genereert eenvoudig overeenkomsten met de reguliere expressie.

#2

Converteer naar een array, pas String#each_char toe dan Enumerable#each_consa>, dan Enumerable#count:

def count_em(str, substr)
  subarr = substr.chars
  str.each_char
     .each_cons(substr.size)
     .count(subarr)
end
count_em(str,"aa")
  #=> 5
count_em(str,"ab")
  #=> 2

We hebben:

subarr = "aa".chars
  #=> ["a", "a"]
enum0 = "aaabbccaaaaddbab".each_char
  #=> #<Enumerator: "aaabbccaaaaddbab":each_char>

We kunnen de elementen zien die door deze enumerator worden gegenereerd door deze naar een array te converteren:

enum0.to_a
  #=> ["a", "a", "a", "b", "b", "c", "c", "a", "a", "a",
  #    "a", "d", "d", "b", "a", "b"]
enum1 = enum0.each_cons("aa".size)
  #=> #<Enumerator: #<Enumerator:
  #      "aaabbccaaaaddbab":each_char>:each_cons(2)> 

Converteer enum1naar een array om te zien welke waarden de enumerator doorgeeft aan 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", "a"],
  #    ["a", "b"]]
enum1.count(subarr)
  #=> enum1.count(["a", "a"])
  #=> 5

Antwoord 2, autoriteit 62%

Het is omdat de counttelt tekens, niet instanties van tekenreeksen. In dit geval betekent 'aa'hetzelfde als 'a', het wordt beschouwd als een reeks tekens om te tellen.

Het aantal keren tellen dat aain de tekenreeks voorkomt:

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

Antwoord 3

probeer te gebruiken
string.split(‘a’).count – 1

Other episodes