2016-05-12 9 views
0

Ich schreibe ein Filterprogramm, liest eine CSV-Datei mit Adressdaten und schließt Zeilen aus, die in einem Crescent (Cres), Avenue (Ave) oder Ort (Pl) befinden.Chaning Ruby Regexp-Operatoren

Hier einige Beispiel-Eingang:

data = <<CSV 
ID,Street address,Town,Valuation date,Value 
1,1 Northburn RD,WANAKA,1/1/2015,280000 
2,1 Mount Ida PL,WANAKA,1/1/2015,280000 
3,1 Mount Linton AVE,WANAKA,1/1/2015,780000 
4,1 Centre CRES,WANAKA,1/1/2015,295000 
CSV 

require 'csv' 

elements = [] 
CSV.parse(data, headers: true, header_converters: :symbol) do |row| 
    elements << row.to_h 
end 
elements 
#=> [ 
#  {:id=>"1", :street_address=>"1 Northburn RD", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"280000"}, 
#  {:id=>"2", :street_address=>"1 Mount Ida PL", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"280000"}, 
#  {:id=>"3", :street_address=>"1 Mount Linton AVE", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"780000"}, 
#  {:id=>"4", :street_address=>"1 Centre CRES", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"295000"} 
# ] 

ich einfache reguläre Ausdrücke für eine der drei filtern können, dh /pl/, /cres/ und /ave/, aber ich kann sie && nicht Kette mit: (noch tun sie funktionieren, wenn ich sie in drei separate „Filter“ aufgespalten)

elements.select { |e| e[:street_address].downcase! !~ /pl/ && e[:street_address].downcase! !~ /cres/ && e[:street_address].downcase! !~ /ave/ } 
#=> [ 
#  {:id=>"1", :street_address=>"1 northburn rd", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"280000"}, 
#  {:id=>"3", :street_address=>"1 mount linton ave", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"780000"}, 
#  {:id=>"4", :street_address=>"1 centre cres", :town=>"WANAKA", :valuation_date=>"1/1/2015", :value=>"295000"} 
# ] 

Dieser filtert Eintrag # 2 wie erwartet, aber nicht # 3 und # 4.

Irgendwelche Ideen, was ich vermisse?

+1

Ist der Code der CSV-Datei zu Ihrer Frage zu lesen? (Sie sollten übrigens die [CSV] (http://ruby-doc.org/stdlib-2.3.1/libdoc/csv/rdoc/CSV.html) Bibliothek von Ruby verwenden. – Stefan

+0

Nein, es funktioniert nicht . Nur der Filter Teil ist zwielichtig, aber ich dachte, ich würde alles für den Fall enthalten :) Ich werde auch in die CSV-Bibliothek schauen! –

+0

Es ist normalerweise besser, Code zu schreiben, den andere nur kopieren und einfügen können. Könnten Sie einige Beispieldaten für "Elemente" und die erwartete Ausgabe hinzufügen? – Stefan

Antwort

5

Es ist wegen downcase! - es verändert den Empfänger und es kehrt nil wenn keine Änderungen vorgenommen wurden.

str = 'FOO' 
str.downcase! #=> "foo" 
str.downcase! #=> nil 

Daher Ihr zweiter Vergleich wird nil !~ /cres/ die immer true ist.

Code zu beheben, verwenden downcase (ohne !):

elements[:streetAddress] !~ /pl/i 

Des Weiteren Sie kombinieren können:

elements[:streetAddress].downcase !~ /pl/ 

oder eine i zu Ihrem regulären Ausdruck hinzuzufügen Groß- und Kleinschreibung zu machen Ihre regulären Ausdrücke und Verwendung reject:

elements.reject { |e| e[:streetAddress] =~ /pl|cres|ave/i } 

Um nur Matchstrings, die Ende mit „pl“, „cres“ oder „all“, eine geeigneten anchor zu verwenden, zum Beispiel /(pl|cres|ave)$/i

+0

das ... ist ein anständiger Punkt ... also würde ich drei separate upcase/downcase Konvertierungen tun? Das scheint mir etwas rückständig zu sein. –

+0

@TinusWagner natürlich nicht, ich habe meine Antwort mit einer Alternative aktualisiert. – Stefan

+0

Sie sind eine Legende. Vielen Dank. –

0

Wenn Sie Elemente aus einem Array auf der Grundlage einer Bedingung zu entfernen, die idiomatische Weg könnte Array#delete_if

IMO, versuchen zu benutzen, nicht Regex zu verwenden, wenn Sie bereits wissen, welche Werte akzeptiert werden. Regex eignen sich hervorragend für die Mustererkennung (Überprüfung der E-Mail-Gültigkeit und dergleichen), aber ihre Verwendung sollte nicht weiter gehen.

Unter der Annahme, RD, CRES, AVE sind immer auf dem letzten Wort, das funktioniert:

x = elements.delete_if do |el| 
    ['pl', 'cres', 'ave'].include?(el[:streetAddress].downcase.split.last) 
end 
+0

hey floum, wenn wir einfach 'pl' zum Beispiel als eine remove-Bedingung dann wird es nicht funktionieren, wenn die vollständige Zeichenfolge für streetAddress ist "55 Mt Gold AVE" zum Beispiel richtig? –

+0

Ich habe gesehen, dass Sie Daten von CSV eingereicht haben, nachdem ich geantwortet habe. Ich muss das überprüfen und in einigen wenigen auf Sie zurückkommen. – floum

+1

danke für deine Mühe @floum –