我有一个地址类,它使用正则表达式从地址的第一行解析门牌号,街道名称和街道类型。这段代码通常运作良好,但我在这里发帖与社区分享,看看是否有人有改进建议。
注意:STREETTYPES和QUADRANT常量分别包含所有相关的街道类型和象限。
我在这里添加了一个子集:
private const string STREETTYPES = @"ALLEY|ALY|ANNEX|AX|ARCADE|ARC|AVENUE|AV|AVE|BAYOU|BYU|BEACH|...";
private const string QUADRANTS = "N|NORTH|S|SOUTH|E|EAST|W|WEST|NE|NORTHEAST|NW|NORTHWEST|SE|SOUTHEAST|SW|SOUTHWEST";
HouseNumber,Quadrant,StreetName和StreetType都是该类的所有属性。
private void Parse(string line1)
{
HouseNumber = string.Empty;
Quadrant = string.Empty;
StreetName = string.Empty;
StreetType = string.Empty;
if (!String.IsNullOrEmpty(line1))
{
string noPeriodsLine1 = String.Copy(line1);
noPeriodsLine1 = noPeriodsLine1.Replace(".", "");
string addressParseRegEx =
@"(?ix)
^
\s*
(?:
(?<housenumber>\d+)
(?:(?:\s+|-)(?<quadrant>" +
QUADRANTS +
@"))?
(?:(?:\s+|-)(?<streetname>\S+(?:\s+\S+)*?))??
(?:(?:\s+|-)(?<quadrant>" +
QUADRANTS + @"))?
(?:(?:\s+|-)(?<streettype>" + STREETTYPES +
@"))?
(?:(?:\s+|-)(?<streettypequalifier>(?!(?:" +
QUADRANTS +
@"))(?:\d+|\S+)))?
(?:(?:\s+|-)(?<streettypequadrant>(" +
QUADRANTS + @")))??
(?:(?:\s+|-)(?<suffix>(?:ste|suite|po\sbox|apt)\s*\S*))?
|
(?:(?:po|postoffice|post\s+office)\s+box\s+(?<postofficebox>\S+))
)
\s*
$
";
Match match = Regex.Match(noPeriodsLine1, addressParseRegEx);
if (match.Success)
{
HouseNumber = match.Groups["housenumber"].Value;
Quadrant = (string.IsNullOrEmpty(match.Groups["quadrant"].Value)) ? match.Groups["streettypequadrant"].Value : match.Groups["quadrant"].Value;
if (match.Groups["streetname"].Captures.Count > 1)
{
foreach (Capture capture in match.Groups["streetname"].Captures)
{
StreetName += capture.Value + " ";
}
StreetName = StreetName.Trim();
}
else
{
StreetName = (string.IsNullOrEmpty(match.Groups["streetname"].Value)) ? match.Groups["streettypequalifier"].Value : match.Groups["streetname"].Value;
}
StreetType = match.Groups["streettype"].Value;
//if the matched street type is found
//use the abbreviated version...especially for credit bureau calls
string streetTypeAbbreviation;
if (StreetTypes.TryGetValue(StreetType.ToUpper(), out streetTypeAbbreviation))
{
StreetType = streetTypeAbbreviation;
}
}
}
}
答案 0 :(得分:8)
享受地址和正则表达式的乐趣,你可以进行长时间的恐怖游戏。
你正试图在混乱中下令。
对于每一个“123简单方式”,都有一个“14 1/2南”。
然后,为了额外的笑声,那里有盐湖城:“855 South 1300 East”。
玩得开心。
街头地址的例外情况多于规则。
答案 1 :(得分:6)
我不知道您所在的国家/地区,但如果您在美国并希望在地址验证上花一些钱,则可以购买相关的USPS产品here。并且here是从USPS中找到预期单词和缩写的免费单词列表的好地方。我相信其他国家/地区也可以使用类似页面。
答案 2 :(得分:6)
我认为你应该澄清你的使用场景。
除非你处于非常非常有限的情况下,你知道地址是按照严格的模式输入的,解析内容的地址是一个非常难以解决的问题,而且通常非常徒劳(除非它是你的申请中的raison d'être。
如果您仅限于某个具有非常具体的写地址惯例的国家/地区,那么使用这些正则表达式可能会让您获得90%的权限。
但是,一旦你必须开始接受外国地址,你就被搞砸了
即使您是以美国为中心的网站,也很可能您必须能够接受居住在国外的美国公民的地址。
同样,在非常狭窄的领域中可能没问题,但是在用户输入时,验证或拆分未经严格验证和约束的地址几乎总是一个坏主意。
当你为用户强制执行一些严格的规则来输入他们的地址时,这些最终结果在一小部分情况下是不够的,即使在最好的地址验证组件中也是如此。
只是搞乱地址解析的一些事情:
底线是
如果以可解析的格式获取地址非常重要,请100%确定您可以正确获得所有可能的组合,否则您将获得一定比例的失败,这将意味着用户受挫和销售损失。
如果您没有100%的案例覆盖范围,则不要对用户强制执行严格的规则
我无法计算我放弃购买的网站数量,因为当我居住的地方没有时,我们需要邮政编码。
很抱歉这个咆哮,但我认为重要的是,想要进行地址验证和解析的人会认真思考他们自己所处的内容。
答案 3 :(得分:2)
这实际上很有效,除了它不会拉公寓号码。我们正在努力。当我们有一个769 Branch Ave的地址时,它也有点咳嗽。当然,“分支”是其寻找的街道类型之一。这一切都可以追溯到混乱的事情。我们知道它会在这里和那里打破。
答案 4 :(得分:1)
如果有人在2013/2014遇到此问题:) 您可以使用Google地理编码API。它提供的功能不仅仅是正则表达式 - 你甚至可以获得lat / long的地址。它是免费的
对于地址示例 -
答案 5 :(得分:0)
我试图让它工作,但似乎你有一个StreetTypes类的静态成员,但不包括在内。它似乎除了那之外有用,但没有它我就做不了多少测试。
答案 6 :(得分:0)
我同意你的严格性会成为一个问题。我正在编写一个地址解析器,旨在从分类广告中剥离地址,其格式可以是任何东西。例如,对于您的象限匹配,您完全忽略了标点符号。我必须以所有这些不同的方式搜索可能代表NE的数据:
“NE”,“N.E”,“N E”,“N.E。”,“N。E”,“North East”,“Northeast”
所以我使用以下模式匹配,无论表达方式如何,都应该捕获所有方向限定符:
\b(?:(?:[nesw]\.? ?){0,2}|(?:north|no\.|east|south|so\.|west){0,2})\b
当然,背景也很重要,因为“不”将与此相匹配。但是内布拉斯加州的“NE”将与之相匹配,所以你必须要小心你的大表达中左右两边的内容。我不得不编制通常出现在地址文本中的单词列表,这些单词不是地址组件,例如“near,x-street,in,across”等。
这是一个非常棘手的问题,我同意盐湖城是一个婊子。除了具有双向/坐标格式之外,它们还通过引用诸如“3700 North 5300 East Arborville Way”之类的东西来复合它,其中街道可以通过名称,数字或两者来引用。