【问题标题】:Regex to match address with subpatterns正则表达式将地址与子模式匹配
【发布时间】:2021-11-05 04:41:05
【问题描述】:

我正在尝试创建一个正则表达式来将地址解析为五个部分:“address1”,即街道地址,“address2”,即公寓号码或地址第 2 行上显示的任何其他内容,城市、州和邮政编码。

当我运行它时,Python(或 Django)在我运行 re.search 时抛出一个错误,指出“模式意外结束”。谁能告诉我如何修改这个正则表达式以正确匹配?

我是一个正则表达式菜鸟。我可以弄清楚这个应该做什么,但我自己永远写不出来。我是从 http://regexlib.com/REDetails.aspx?regexp_id=472 那里得到的。

re.compile(r"""
(?x)^(?n:
(?<address1>
    (\d{1,5}(\ 1\/[234])?(\x20[A-Z]([a-z])+)+ )
    | (P.O. Box \d{1,5}))\s{1,2}
(?<city>
    [A-Z]([a-z]) 
        + (\.?)(\x20[A-Z]([a-z])+){0, 2})\, \x20
(?<state>
    A[LKSZRAP] | C[AOT] | D[EC] | F[LM] | G[AU] | HI
    | I[ADL N] | K[SY] | LA | M[ADEHINOPST] | N[CDEHJMVY]
    | O[HKR] | P[ARW] | RI | S[CD] | T[NX] | UT | V[AIT] 
    | W[AIVY] 
    | [A-Z]([a-z])
        + (\.?)(\x20[A-Z]([a-z])+){0,2})\x20
(?<zipcode>
    (?!0{5})\d{5}(-\d {4})?)
)$"
""", re.VERBOSE)

为可读性添加了换行符。作为一个后续问题,这个正则表达式是否可以像这样分成多行以提高可读性,还是需要全部放在一行中才能工作(我想我可以连接单独的行)?

附:我知道这闻起来像家庭作业,但实际上是为了工作。

编辑:请求了正在使用的实际代码,所以在这里。我把它省略了,因为这里的所有东西实际上都已经在那里了,但也许它会有所帮助。

该函数是 Django 视图的一部分,但这对我们的目的来说应该没有太大关系。

def parseAddress(address):
  pattern = r"^(?n:(?<address1>(\d{1,5}(\ 1\/[234])?(\x20[A-Z]([a-z])+)+ )|(P\.O\.\ Box\ \d{1,5}))\s{1,2}(?i:(?<address2>(((APT|APARTMENT|BLDG|BUILDING|DEPT|DEPARTMENT|FL|FLOOR|HNGR|HANGER|LOT|PIER|RM|ROOM|S(LIP|PC|T(E|OP))|TRLR|TRAILER|UNIT)\x20\w{1,5})|(BSMT|BASEMENT|FRNT|FRONT|LBBY|LOBBY|LOWR|LOWER|OFC|OFFICE|PH|REAR|SIDE|UPPR|UPPER)\.?)\s{1,2})?)(?<city>[A-Z]([a-z])+(\.?)(\x20[A-Z]([a-z])+){0,2})\, \x20(?<state>A[LKSZRAP]|C[AOT]|D[EC]|F[LM]|G[AU]|HI|I[ADL N]|K[SY]|LA|M[ADEHINOPST]|N[CDEHJMVY]|O[HKR]|P[ARW]|RI|S[CD] |T[NX]|UT|V[AIT]|W[AIVY]|[A-Z]([a-z])+(\.?)(\x20[A-Z]([a-z])+){0,2})\x20(?<zipcode>(?!0{5})\d{5}(-\d {4})?))$"
  match = re.search(pattern, address)

我使用我的家庭住址作为输入,但我也尝试使用“123 Main St., Austin, TX 12345”作为输入,结果相同。

【问题讨论】:

  • 是的,您可以使用详细的正则表达式模式(docs.python.org/py3k/howto/regex.html#regex-howto 并在底部找到 re.VERBOSE):您能否提供准确的代码示例,以便人们可以尝试重现您的错误得到了吗?
  • 开头的引号前面应该有r,以使其成为“原始字符串”,其中反斜杠没有特殊含义。
  • @steabert,我会查看 re.VERBOSe 文档。感谢那。我还发布了您要求的代码示例。错误显示在包含 `match = re.search(pattern, address) 的行上
  • @Tom Zych:谢谢,我把它放到代码中,我会用它来修改问题。
  • 看起来模式中的某处有错误,可能缺少括号或其他什么?我劝你不要只是复制粘贴正则表达式,只会让人头疼……

标签: python regex


【解决方案1】:

有些人可能不认为这是一个答案,但请耐心等待一分钟。

我强烈建议不要尝试使用正则表达式解析街道地址。街道地址在任何意义上都不是“常规”。有无限的变化,除非您将自己限制在非常有限的语法上,否则总会有您无法解析的字符串。大量的时间和金钱已经投入到解析地址的解决方案上,首先是美国邮局和许多列表清理服务提供商。只需谷歌“解析街道地址”即可了解问题的范围。有商业解决方案和一些免费解决方案,但网络上的 cmets 表明没有人总是正确的。

我也是根据经验说话的。 80 年代,我在一家数据库排版公司工作,我们不得不解析地址。我们从未能够开发出完美运行的解决方案,并且对于我们自己捕获的数据(我们有一个大型键盘输入部门),我们开发了一种特殊的符号语法,以便操作员可以在适当的位置插入分隔符以帮助解析过程。

看看那里的一些免费服务。您将为自己省去很多麻烦。

【讨论】:

    【解决方案2】:

    在正则表达式中设置x(详细)标志,即:(?x)

    【讨论】:

    • 您是否建议使用r"^(?x:(?&lt;address1&gt;... 而不是"^(?n:(?&lt;address1&gt;?我用开引号前面的 r 修改了问题和我的代码。
    • 好的,我修改了 VERBOSE 正则表达式来做到这一点。是你的意思吗?
    • @Caleb,对不起,我的错字。 (?x)
    【解决方案3】:

    一个非正则表达式的答案:查看 python 库 usaddress(还有一个 web interface 用于尝试)

    同意 Jim 的观点,这里的正则表达式不是一个好的解决方案。 usaddress 以概率方式解析地址,在处理混乱的地址时,它比基于正则表达式的解析器更加健壮。

    【讨论】:

      【解决方案4】:

      您的正则表达式在第一个字符 n 上失败,您可以按如下方式进行验证。创建一个文件test.py 并输入以下内容:

       import re
       re.compile(r'...')
      

      当然是在哪里填写你的模式:) 现在运行python -m pdb test.py,输入c 继续,当引发异常时它将停止。此时键入l 以查看您在代码中的位置。您会看到它失败了,因为source.next 不在FLAGS 中。这个source 只是你的模式,所以你可以通过输入print source.index 来验证它失败的地方。

      此外,删除前面的 n,该模式在 &lt;address1&gt; 的第一个 a 处失败。

      (?n 很奇怪,我在文档中找不到它,所以它似乎是一个不受支持的扩展。至于?&lt;address1&gt;,我觉得应该是?P&lt;address1&gt;。它还有更多问题,例如(?i:,如果我删除这些并修复?P&lt; 的东西,我会在最后一个括号中收到关于不平衡括号的错误。

      【讨论】:

        【解决方案5】:

        Jim Garrison(上图)是正确的 - 地址变化太大,无法使用正则表达式进行解析。我在一家地址验证软件公司工作 - SmartyStreets。试试我们的LiveAddress API - REST 端点提供了所有地址组件,这些组件都解析为一个漂亮、易于使用的 JSON 响应。这是一个示例:

        https://github.com/smartystreets/LiveAddressSamples/blob/master/python/street-address.py

        【讨论】:

        • 这不是假设我已经将地址解析为街道、城市、邮编等吗?
        • 好问题。当前版本的 API 支持在 city 或 lastline 参数中填充 City、State 和 ZIP Code。因此,如果您可以将地址一分为二(街道地址和其他所有地址),那么您可以使用 API 进一步解析它。这个(显然)的棘手部分是确定街道地址的结束位置和最后一行信息的开始位置。我们计划在其中提供整个地址的附加输入字段,但此功能必须封装地址数据中的大量差异。请继续关注 (blog.smartystreets.com)...
        猜你喜欢
        • 2012-05-17
        • 2011-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-20
        • 2022-12-07
        • 2016-12-15
        • 2012-03-12
        相关资源
        最近更新 更多