用于解析邮件地址的正则表达式

时间:2009-03-13 13:06:04

标签: c# regex

我有一个地址类,它使用正则表达式从地址的第一行解析门牌号,街道名称和街道类型。这段代码通常运作良好,但我在这里发帖与社区分享,看看是否有人有改进建议。

注意: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;
                }
            }
        }

    }

7 个答案:

答案 0 :(得分:8)

享受地址和正则表达式的乐趣,你可以进行长时间的恐怖游戏。

你正试图在混乱中下令。

对于每一个“123简单方式”,都有一个“14 1/2南”。

然后,为了额外的笑声,那里有盐湖城:“855 South 1300 East”。

玩得开心。

街头地址的例外情况多于规则。

答案 1 :(得分:6)

我不知道您所在的国家/地区,但如果您在美国并希望在地址验证上花一些钱,则可以购买相关的USPS产品here。并且here是从USPS中找到预期单词和缩写的免费单词列表的好地方。我相信其他国家/地区也可以使用类似页面。

答案 2 :(得分:6)

我认为你应该澄清你的使用场景。

除非你处于非常非常有限的情况下,你知道地址是按照严格的模式输入的,解析内容的地址是一个非常难以解决的问题,而且通常非常徒劳(除非它是你的申请中的raison d'être

如果您仅限于某个具有非常具体的写地址惯例的国家/地区,那么使用这些正则表达式可能会让您获得90%的权限。
但是,一旦你必须开始接受外国地址,你就被搞砸了 即使您是以美国为中心的网站,也很可能您必须能够接受居住在国外的美国公民的地址。

同样,在非常狭窄的领域中可能没问题,但是在用户输入时,验证或拆分未经严格验证和约束的地址几乎总是一个坏主意。
当你为用户强制执行一些严格的规则来输入他们的地址时,这些最终结果在一小部分情况下是不够的,即使在最好的地址验证组件中也是如此。

只是搞乱地址解析的一些事情:

  • 邮政编码(邮政编码)有时会放在之前,之后,甚至根本不存在。
  • 邮政编码遵循严格的规则:10位数的邮政编码可能很容易被发现为无效,但是不存在的邮政编码呢?那么更多的代码如英国使用的代码呢?
  • 香港这样的地方怎么样,你可以用英文,繁体中文或普通话写地址?
  • 如果将您的地址拆分并按顺序写出来,那该怎么办?
  • 即使您只是解析美国地址,也至少有一些方法来描述邮政信箱:您还可以使用 poste restante 一般交付然后需要在Zip代码中添加一个4位数的代码,这通常可能根本不存在......

底线是

如果以可解析的格式获取地址非常重要,请100%确定您可以正确获得所有可能的组合,否则您将获得一定比例的失败,这将意味着用户受挫和销售损失。
如果您没有100%的案例覆盖范围,则不要对用户强制执行严格的规则 我无法计算我放弃购买的网站数量,因为当我居住的地方没有时,我们需要邮政编码。

很抱歉这个咆哮,但我认为重要的是,想要进行地址验证和解析的人会认真思考他们自己所处的内容。

答案 3 :(得分:2)

这实际上很有效,除了它不会拉公寓号码。我们正在努力。当我们有一个769 Branch Ave的地址时,它也有点咳嗽。当然,“分支”是其寻找的街道类型之一。这一切都可以追溯到混乱的事情。我们知道它会在这里和那里打破。

答案 4 :(得分:1)

如果有人在2013/2014遇到此问题:) 您可以使用Google地理编码API。它提供的功能不仅仅是正则表达式 - 你甚至可以获得lat / long的地址。它是免费的

对于地址示例 -

http://maps.googleapis.com/maps/api/geocode/xml?address=2520%20Cohasset%20Rd%20-%20Chico%2C%20CA%2095973-1307%20530-893-1300%20%20&sensor=false

enter image description here

答案 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”之类的东西来复合它,其中街道可以通过名称,数字或两者来引用。