我正在将地址处理为数据库的各自字段格式。我可以得到房屋号码和街道类型,但试图确定最好的方法来获得没有数字和最后一个字的街道。收到的标准街道地址是:
res[:address] = '7707 Foo Bar Blvd'
截至目前,我可以解析以下内容:
house = res[:address].gsub(/\D/, '')
street_type = res[:address].split(/\s+/).last
我的第一个挑战是如何获得'Foo Bar'。请注意,街道名称可以是一个,两个或三个单词。我正在努力为Ruby找到一个单行表达式解决方案。
我的第二个问题是如何改进'house'代码来处理最后有alpha的门牌号码。例如,“7707B”。
最后,如果您可以参考一个好的备忘单,其中包含有助于这些表达的示例。
答案 0 :(得分:11)
如果可能的话,我建议使用一个库,因为地址解析可能很困难。查看Indirizzo Ruby gem,这样可以轻松实现:
require 'Indirizzo'
address = Indirizzo::Address.new("7707 Foo Bar Blvd")
address.number
=> "7707"
address.street
=> ["foo bar blvd", "foo bar boulevard"]
即使您不使用Indirizzo库本身,阅读其源代码可能非常有用,看看他们如何解决问题。例如,它对正则表达式进行了精细调整,以匹配地址的不同部分:
Match = {
# FIXME: shouldn't have to anchor :number and :zip at start/end
:number => /^(\d+\W|[a-z]+)?(\d+)([a-z]?)\b/io,
:street => /(?:\b(?:\d+\w*|[a-z'-]+)\s*)+/io,
:city => /(?:\b[a-z][a-z'-]+\s*)+/io,
:state => State.regexp,
:zip => /\b(\d{5})(?:-(\d{4}))?\b/o,
:at => /\s(at|@|and|&)\s/io,
:po_box => /\b[P|p]*(OST|ost)*\.*\s*[O|o|0]*(ffice|FFICE)*\.*\s*[B|b][O|o|0][X|x]\b/
}
源代码中的这些文件可以提供更多细节:
(但我也普遍同意@ drhenner的评论,为了让自己更容易,你可能只是在不同的领域接受这些数据输入。)
编辑:要提供有关如何删除街道后缀(例如“Blvd”)的更具体的答案,您可以使用Indirizzo的正则表达式常量(例如Suffix_Type
来自{ {1}})像这样:
constants.rb
(注意我还将address = Indirizzo::Address.new("7707 Foo Bar Blvd", :expand_streets => false)
address.street.map {|street| street.gsub(Indirizzo::Suffix_Type.regexp, '').strip }
=> ["foo bar"]
传递给初始化程序,以避免同时扩展“Blvd”和“Boulevard”替代方案,因为我们无论如何都要丢弃后缀。)
答案 1 :(得分:2)
你可以在正则表达式
中快速松散地使用命名捕获组matches = res[:address].match(/^(?<number>\S*)\s+(?<name>.*)\s+(?<type>.*)$/)
number = matches[:number]
house = matches[:name]
street_type = matches[:type]
或者如果您希望您的正则表达式更准确,您可以替换的类型
(?<type>.*)
同
(?<type>(Blvd|Ave|Rd|St))
并添加您想要的所有不同选项
答案 2 :(得分:1)
你可以使用类似的东西:
^\S+ (.+?) \S+$
\S
匹配任何非空格字符
^
匹配字符串的开头
$
匹配字符串
(.+?)
捕获两者之间的任何内容。
答案 3 :(得分:0)
仔细检查数据集以确定是否尚未处理此问题。
我花了相当多的时间首先创建一个可能街道名称结尾的分类,使用正则表达式条件试图从完整的地址字符串中取出街道号码,然后结果是我的shapefile的属性表已经已经细分了这些组件。
在你继续解析地址字符串的过程之前,由于不可避免的奇怪变化(一些包裹地址用于内陆地块并且有奇怪的地址等)总是有点苦差事,所以确保你的数据集没有我已经为你做了这个!!!
但如果不这样做,请运行地址字符串,address.split(" ")
创建一个'words'数组。在大多数情况下,第一个“单词”是街道号码。这适用于我的地址的约95%。 (注意:我的:地址字符串不包含城市,县,州,邮编,它们只是本地地址)
我浏览了整个地址,并从每个地址中拨出最后一个“字”。检查了这个阵列&amp;拔出任何不是“Lane”,“Road”,“Rd”或其他什么的“单词”。从这个地址结尾列表中我创建了这个巨大的匹配正则表达式对象
streetnm_endings = street_endings.map {|s| /#{s}/ }
endings_matches = Regexp.union(street_endings)
我遍历每个地址字符串shift
- 输出第一个数组成员,因为这几乎总是街道号码。然后gsub out the street endings得到街道名称sans街道号码或街道名称结尾,这些数据库通常不喜欢:
parcels.each do |p|
remainder = p.address.split(" ")
p.streetnum = remainder.shift
p.streetname = remainder.join(" ").gsub(endings_matches, "")
p.save
end
它并不总是有效,但大部分时间都有效。
答案 4 :(得分:0)
我目前只是将我给予的任何内容传递给googlemaps并让他们发回一个非常容易解析的格式化街道地址。
function addressReview(addressInput) {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
geocoder.geocode( { 'address': addressInput}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
var addr = results[0].formatted_address;
var latTi = results[0].geometry.location.lat();
var lonGi = results[0].geometry.location.lng();
$.post('/welcome/gcode',{ add: addr , la: latTi , lo: lonGi });
$('#cust_addy').val(addr);
} else {
$('#cust_addy').attr("placeholder",'Cannnot determine location');
}
} else {
$('#cust_addy').attr("placeholder",'Cannnot determine location');
}
});
}
在那之后,我把它分成红宝石。与.split(',')和.split('')