正则表达式:解析街道名称/号码
Posted
技术标签:
【中文标题】正则表达式:解析街道名称/号码【英文标题】:Regex: Parse streetname/number 【发布时间】:2011-06-28 05:22:27 【问题描述】:C#/.NET 2.0
我需要在两个单独的值中解析一个包含街道名称和房屋编号的字符串。
in: "Streetname 1a" out: "streetname" "1a"
"Street name 1a" "street name" "1a"
"Street name 1 a" "street name" "1 a"
我的第一个选择是拆分我找到“”字符的字符串,但这不适用于第二种情况。
result[0] = trimmedInput.Substring(0, splitPosition).Trim();
result[1] = trimmedInput.Substring(splitPosition + 1).Trim();
最好的方法是什么?我可以使用正则表达式吗?
谢谢
【问题讨论】:
数据存储在哪里?你不能以不同的方式坚持它,以它更喜欢的格式吗? 【参考方案1】:^(.+)\s(\S+)$
应该可以解决问题
编辑:如果门牌号码中不能有空格,这将起作用。否则这个问题不能通过程序来解决,因为程序永远不会知道字符串标记的语义。
房屋地址混乱且不一致。我处理的是地址数据,老实说,如果你没有标准化形式的数据,你基本上就完蛋了。
^(.+)\s(\d+(\s*[^\d\s]+)*)$
将涵盖更多案例,但如果我见过这样的模式,那就像一罐蠕虫。
【讨论】:
@thedev:我认为我的最后一次编辑将通过所有 3 项测试,但它不可避免地会在其他一些你现在甚至想不到的测试中失败。 最后一次编辑通过了这 3 个测试......它还输出了一个值,在这些情况下总是“a”,我们可以删除这第三个 val 吗? @thedev:你是什么意思?我想你需要 Groups[1] 和 Groups[2] 我还得到了最后一个正则表达式的 Groups[3] 是的,我知道,但你总会明白的。只需使用您需要的。【参考方案2】:你必须更清楚地定义你正在寻找的模式,假设甚至有一个。需要有一些你可以做出的一般性观察将永远成立:
街道地址由名称和数字组成。 名称总是出现在第一位。 名称由一个或多个单词组成,以空格分隔。 数字是一个数字,后跟一个可选字母。根据评论,最后一点并不完全正确,因为街道号码的数字和字母部分可以用空格分隔。
如果您不能保证街道名称和号码的顺序,并且街道名称中的单词不包含数字,那么我不确定是否有任何帮助。
以下正则表达式应涵盖大多数情况:
Regex reggie = new Regex(@"^(?<name>\w[\s\w]+?)\s*(?<num>\d+\s*[a-z]?)$", RegexOptions.IgnoreCase)
【讨论】:
使用 \w 是个坏主意。一些像“Rue d'Alembert”这样的法国街道不符合条件,等等。 那你也得考虑 ' ()。【参考方案3】:正如 Dyppl 所说,街道地址很混乱。但是,如果您的地址数据代表美国地址并且您拥有完整的地址(包括城市、州和/或邮政编码),您可以使用地址验证服务来解析(和验证!)和标准化组件。我为地址验证提供商SmartyStreets 工作。这是我不久前编写的一个快速 C# 示例,它调用我们的 LiveAddress API:
https://github.com/smartystreets/LiveAddressSamples/blob/master/c-sharp/street-address.cs
这是该示例的结果输出(请注意,街道名称和主要编号在“组件”部分中解析):
[
"input_index": 0,
"candidate_index": 0,
"delivery_line_1": "3214 N University Ave",
"last_line": "Provo UT 84604-4405",
"delivery_point_barcode": "846044405140",
"components":
"primary_number": "3214",
"street_predirection": "N",
"street_name": "University",
"street_suffix": "Ave",
"city_name": "Provo",
"state_abbreviation": "UT",
"zipcode": "84604",
"plus4_code": "4405",
"delivery_point": "14",
"delivery_point_check_digit": "0"
,
"metadata":
"record_type": "S",
"county_fips": "49049",
"county_name": "Utah",
"carrier_route": "C016",
"congressional_district": "03",
"latitude": 40.27586,
"longitude": -111.6576,
"precision": "Zip9"
,
"analysis":
"dpv_match_code": "Y",
"dpv_footnotes": "AABBR1",
"dpv_cmra": "Y",
"dpv_vacant": "N",
"ews_match": false
]
我们为使用率低的用户提供完全免费的订阅服务。这是一个解释所有字段的链接:
http://wiki.smartystreets.com/liveaddress_api_users_guide#json-responses
编辑:包括纬度/经度字段(新发布)。
【讨论】:
现在只是 USPS 地址。查看 www.worldaddresses.com 或 www.strikeiron.com 了解国际地址处理。 你可以尝试任何你想要的正则表达式,但是除非你能从地址标准化服务中得到一个标准化的地址对象,否则这将是非常困难的,并且很难保证正确性【参考方案4】:首先你应该尝试使用String.LastIndexOf()
在可能的位置拆分来找到数字。
之后,您应该检查最后一组中的任何字符是否包含任何数字,例如splittedValue.Any(c => Char.IsDigit(c));
。因此,如果您在最后一组中找到任何数字,您可以确定您的拆分是正确的,但可能存在与此行为不匹配的地址。
更新
如果你真的有如此嘈杂的数据必须标准化,我认为你不能做得更好,那么@Dyppl 说并使用一些复杂的正则表达式必须通过你得到的样本来进化,这是行不通的。
【讨论】:
输入字符串的另一种可能性是:“street name 1 a”,在这种情况下,我也会得到错误的输出【参考方案5】:这是假设您所有的“地址”都将采用上述至少一种方式进行格式化。
string address = "Streetname 1a"
string street = Regex.Replace(address, "^[^0-9]+", "");
string number = address.Replace(street, "");
然后修剪这两个值。
【讨论】:
很有趣,如果我们可以排除这个数字,这可能会起作用。考虑到街道名称不包含任何数字 我已将正则表达式更新为可能有效的内容(即排除 nuber):) 您确实知道街道名称中带有数字,对吧?比如,在纽约 是的,我意识到这一点 :) 这就是为什么我说“这是假设您所有的“地址”将至少以上述方式之一进行格式化。”另外,我认为每个人都意识到这个问题是无法解决的,因为地址可能有数百种不同的格式。我只是提供一个简单的解决方案,以防 OP 只需要涵盖他作为示例提供的格式。 @Craigt:好的,没有冒犯的意思以上是关于正则表达式:解析街道名称/号码的主要内容,如果未能解决你的问题,请参考以下文章
在 Bigquery 中使用正则表达式获取地址的街道名称和编号