Chaning Ruby regexp运算符

Tin*_*ner 0 ruby regex

我正在编写一个过滤程序,它读取包含地址数据的CSV文件,并排除位于新月(cres),avenue(ave)或place(pl)中的行.

这是一些示例输入:

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"}
#   ]
Run Code Online (Sandbox Code Playgroud)

我可以使用简单的正则表达式来过滤三个中的一个,即/pl/,/cres//ave/,但我不能使用它们链接它们&&(当我将它们分成三个单独的"过滤器"时它们也不起作用)

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"}
#   ]
Run Code Online (Sandbox Code Playgroud)

这会按预期过滤条目#2,但不过滤#3和#4.

我缺少什么想法?

Ste*_*fan 5

这是因为downcase!- 它改变了接收器,nil如果没有做出改变则返回.

str = 'FOO'
str.downcase! #=> "foo"
str.downcase! #=> nil
Run Code Online (Sandbox Code Playgroud)

因此,你的第二次比较变成了nil !~ /cres/永远true.

要修复代码,请使用downcase(不!):

elements[:streetAddress].downcase !~ /pl/
Run Code Online (Sandbox Code Playgroud)

或者i在正则表达式中添加一个以使其不区分大小写:

elements[:streetAddress] !~ /pl/i
Run Code Online (Sandbox Code Playgroud)

此外,您可以组合正则表达式并使用reject:

elements.reject { |e| e[:streetAddress] =~ /pl|cres|ave/i }
Run Code Online (Sandbox Code Playgroud)

要只匹配字符串结束用"PL","CRES"或"AVE",使用适当的,例如/(pl|cres|ave)$/i