2017-04-25 5 views
0

ein Satz gegeben, möchte ich alle duplizierten Wörter zählen: Es ist ein Exercice von Exercism.io ist Word countEntfernen Sie alle speziellen Zeichen außer appostrophe

Zum Beispiel für die Eingabe "olly olly in come free"

plain olly: 2 in: 1 come: 1 free: 1

ich habe diesen Test für exemple:

def test_with_quotations 
    phrase = Phrase.new("Joe can't tell between 'large' and large.") 
    counts = {"joe"=>1, "can't"=>1, "tell"=>1, "between"=>1, "large"=>2, "and"=>1} 
    assert_equal counts, phrase.word_count 
    end 

das ist meine Methode

def word_count 
    phrase = @phrase.downcase.split(/\W+/) 
    counts = phrase.group_by{|word| word}.map {|k,v| [k, v.count]} 
    Hash[*counts.flatten] 
    end 

Für den Test oben ich diesen Fehler haben, wenn ich es im Terminal laufen:

2) Failure: 
PhraseTest#test_with_apostrophes [word_count_test.rb:69]: 
--- expected 
+++ actual 
@@ -1 +1 @@ 
-{"first"=>1, "don't"=>2, "laugh"=>1, "then"=>1, "cry"=>1} 
+{"first"=>1, "don"=>2, "t"=>2, "laugh"=>1, "then"=>1, "cry"=>1} 

Mein Problem ist, alle Zeichen außer ' Apostroph zu entfernen .. .

die Regex in der Methode fast funktioniert ... phrase = @phrase.downcase.split(/\W+/) aber die Apostrophe entfernen ...

Ich will nicht, um ein Wort das Apostroph halten, 'Hello' =>Hello aber Don't be cruel =>Don'tbecruel

+0

Versuch '/ [^ 'az] /' – dawg

+1

oder dies versuchen: '/ [az' ] +/I' –

+0

es die einfachen Anführungszeichen halten :(@dagw –

Antwort

4

Vielleicht so etwas wie:

string.scan(/\b[\w']+\b/i).each_with_object(Hash.new(0)){|a,(k,v)| k[a]+=1} 

Die Regex beschäftigt Wortgrenzen (\ b). Der Scan gibt ein Array der gefundenen Wörter aus, und für jedes Wort im Array werden sie zum Hash hinzugefügt, der für jedes Element einen Standardwert von Null hat, der dann inkrementiert wird.

Stellt sich meine Lösung aus, während alle Gegenstände und Fall ignoriert werden noch die Elemente im Fall verlassen sie in ursprünglich gefunden wurden. Dies wäre nun eine Entscheidung für Nelly, entweder zu akzeptieren, wie es ist, oder einen Downcase für die ursprüngliche Zeichenfolge oder das Array-Element durchzuführen, wenn es dem Hash hinzugefügt wird.

Ich werde diese Entscheidung überlassen euch :)

+0

Das funktioniert! Können Sie bitte etwas kommentieren und erklären, was es „wirklich tun“ ... –

+0

Nizza ........... – dawg

+3

Wenn 'string =„‚tis Les‘ play“', würde Ihr Code zurückgeben '{ "tis" => 1, "Les" => 1, "play" => 1} ', während die beiden Apostrophe (keine einfachen Anführungszeichen) hätten behalten werden sollen:' {'' tis '=> 1, "Les' "=> 1," play "=> 1}'. Dies ist nicht so sehr eine Kritik an Ihrer Antwort, sondern ein Beweis für die Schwierigkeit, zwischen einfachen Anführungszeichen und Apostrophen zu unterscheiden. –

1

Gegeben:

irb(main):015:0> phrase 
=> "First: don't laugh. Then: don't cry." 

Versuchen:

irb(main):011:0> Hash[phrase.downcase.scan(/[a-z']+/) 
        .group_by{|word| word.downcase} 
        .map{|word, words|[word, words.size]} 
        ] 
=> {"first"=>1, "don't"=>2, "laugh"=>1, "then"=>1, "cry"=>1} 

Mit Ihrem Update, wenn Sie einfache Anführungszeichen entfernen möchten, tun Sie das zuerst:

irb(main):038:0> p2 
=> "Joe can't tell between 'large' and large." 
irb(main):039:0> p2.gsub(/(?<!\w)'|'(?!\w)/,'') 
=> "Joe can't tell between large and large." 

Dann die gleiche Methode verwenden.

Aber Sie sagen - gsub(/(?<!\w)'|'(?!\w)/,'') das Apostroph in 'Twas the night before. entfernen, die ich antworten Sie schließlich einen Parser aufbauen müssen, die den Unterschied zwischen einem Apostroph und Apostroph bestimmen kann, ob /(?<!\w)'|'(?!\w)/ nicht ausreichend ist.

Sie können auch Wortgrenzen verwenden:

irb(main):041:0> Hash[p2.downcase.scan(/\b[a-z']+\b/) 
        .group_by{|word| word.downcase} 
        .map{|word, words|[word, words.size]} 
       ] 
=> {"joe"=>1, "can't"=>1, "tell"=>1, "between"=>1, "large"=>2, "and"=>1} 

Aber das bedeutet nicht 'Tis the night entweder lösen.

+0

Es behalten die einfachen Anführungszeichen '''' –

+0

Aber es erfüllt Anforderungen, TS erwähnt nicht, dass er Anführungsstriche auch entfernen möchte. @Nelly – MikDiet

+0

@Nelly: Das hast du in deinem Beispiel nicht gesagt. Apostrophe zu behalten, aber einfache Anführungszeichen zu entfernen, ist ein schwierigeres Problem, das allein mit einer Regex zu lösen ist. – dawg

0

andere Art und Weise:

str = "First: don't 'laugh'. Then: 'don't cry'." 
reg =/
     [a-z]   #single letter 
     [a-z']+  #one or more letters or apostrophe 
     [a-z]   #single letter 
     '?   #optional single apostrophe 

     /ix   #case-insensitive and free-spacing regex 

str.scan(reg).group_by(&:itself).transfor‌​m_values(&:count) 
    #=> {"First"=>1, "don't"=>2, "laugh"=>1, "Then"=>1, "cry'"=>1} 
+0

Noch funktioniert das unter bestimmten Bedingungen nicht, aber es kann gut genug für Sie sein. –

Verwandte Themen