从字符串中解析可用的街道地址,城市,州,邮政编码

时间:2020-03-05 18:40:46  来源:igfitidea点击:

问题:我从Access数据库中获取了一个地址字段,该地址字段已转换为Sql Server2005. 此字段在一个字段中包含所有内容。我需要将地址的各个部分解析为归一化表中的相应字段。我需要对大约4,000条记录执行此操作,并且它必须是可重复的。

假设:

  • 假设在美国的地址(目前)
  • 假设输入字符串有时会包含一个收件人(正在被寻址的人)和/或者第二个街道地址(即Suite B)
  • 状态可以缩写
  • 邮政编码可以是标准的5位数或者zip + 4
  • 在某些情况下会有错别字

更新:针对提出的问题,没有普遍遵循标准,我需要存储单个值,而不仅是地址编码,而且错误意味着错字(已在上面更正)

样本数据:

  • A.P.Croll&Son 2299 Lewes-Georgetown Hwy,乔治敦,DE 19947
  • 11522 Shawnee Road,格林伍德DE 19950
  • S.W.国王大道144号多佛(DE 19901)
  • 综合建筑。服务2 Penns Way Suite 405 New Castle,德国19720
  • Humes Realty 33 Bridle Ridge Court,刘易斯,德国19958
  • Nichols发掘2742 Pulaski Hwy Newark,DE 19711
  • 19904,士麦那,2284 Bryn Zion Road
  • VEI Dover Crossroads,LLC蛇形路1500号,巴尔的摩MD 21套房100
  • 1990年,杜邦(Dupont)公路北580号,德国(19901)
  • 邮局Box 778 Dover,DE 19903

解决方案

回答

这不会解决问题,但是如果我们仅需要这些地址的经/纬度数据,则Google Maps API会很好地解析未格式化的地址。

回答

地址的记录方式是否有任何标准?例如:

  • 是否总是用逗号或者换行符将street1与street2从城市从zip与州分开?
  • 是否总是明确指出地址类型(道路,街道,林荫大道等)?总是缩写?每个都有吗?
  • 定义"错误"。

我的一般答案是一系列正则表达式,尽管其复杂程度取决于答案。而且,如果根本没有一致性,那么我们可能只能通过Regex取得部分成功(即:过滤出邮政编码和状态),并且必须手动完成其余工作(或者至少非常仔细地完成其余工作仔细检查以确保发现错误)。

回答

我在这种解析上做了很多工作。由于存在错误,我们将无法获得100%的准确度,但是我们可以通过一些方法来获得大部分结果,然后进行可视BS测试。这是解决该问题的一般方法。它不是代码,因为编写代码很学术,没有怪异,只有很多字符串处理。

(现在我们已经发布了一些示例数据,我做了一些小的更改)

  • 向后工作。从邮政编码结尾处开始,该邮政编码将以两种已知格式之一开始:XXXXX或者XXXXX-XXXX。如果未出现,则可以假定我们位于下面的城市州部分中。
  • 在zip之前的下一个内容将是状态,它将以两个字母的格式或者以单词的形式出现。我们也知道这些将是什么-只有50个。此外,我们可以将单词发音,以帮助弥补拼写错误。
  • 在那之前是城市,可能与州在同一条线上。我们可以使用邮政编码数据库根据邮政编码检查城市和州,或者至少将其用作BS检测器。
  • 街道地址通常是一两行。第二行通常是套房号(如果有),但也可以是邮政信箱。
  • 在第一行或者第二行中检测名称几乎是不可能的,尽管如果该名称没有前缀数字(或者如果前缀有" attn:"或者" attention to:",则可能会提示我们是名称还是地址行。

我希望这会有所帮助。

回答

有些数据服务提供的邮政编码将为我们提供该邮政编码中的街道名称列表。

使用正则表达式提取"邮政编码"或者"城市州",找到正确的一个,或者如果两者均出错则找到错误。
从数据源中提取街道列表校正城市和州,然后校正街道地址。获得有效的地址行1,城市,州和邮政编码后,我们就可以在地址行2..3进行假设了。

回答

根据样本数据:

  • 我将从字符串的末尾开始。解析邮政编码(两种格式)。读到第一个空格的结尾。如果未找到邮政编码则错误。
  • 修剪结尾,然后输入空格和特殊字符(逗号)
  • 然后转到状态,再次使用空格作为分隔符。也许使用查找列表来验证2个字母状态代码和完整的状态名称。如果找不到有效状态,则错误。
  • 从末尾再次修剪空格和逗号。
  • 城市变得棘手,实际上我会在此处使用逗号,以免城市中有太多数据。查找逗号或者行首。
  • 如果字符串中还剩下字符,请将所有字符都推到地址字段中。

这并不完美,但是应该是一个很好的起点。

回答

另一个请求样本数据的请求。

如前所述,我将从zip向后进行工作。

有了zip后,我将查询一个zip数据库,存储结果,然后从字符串中删除它们和zip。

这样会使我们地址混乱。 MOST(全部?)地址将以数字开头,因此在剩余的字符串中找到数字的第一个匹配项,然后抓取从该数字到字符串(新)末尾的所有内容。那就是你的地址。该号码左侧的任何内容都可能是收件人。

现在,我们应该将城市,州和邮政编码存储在一个表中,并可能有两个字符串(收件人和地址)。对于地址,检查是否存在"套房"或者"公寓"。等等,然后将其分为两个值(地址行1和2)。

对于收件人,我将平底锅并抓住该字符串的最后一个单词作为姓氏,然后将其余的放到名字字段中。如果我们不想这样做,则需要在开始时检查称呼(先生,女士,博士等),并根据空格的数量对名称进行一些假设捏造。

我认为我们无法以100%的准确度进行解析。

回答

我过去曾经做过。

手动进行操作(构建一个不错的gui来帮助用户快速完成操作),或者使其自动化并根据最近的地址数据库进行检查(我们必须购买)并手动处理错误。

手动处理每个大约需要10秒,这意味着我们每小时可以执行3600/10 = 360,因此4000处理大约需要11-12小时。这将为我们提供较高的准确性。

为了实现自动化,我们需要一个最新的美国地址数据库,并据此调整规则。我建议不要看待正则表达式(很难保持长期,有很多例外)。与数据库进行90%匹配,其余部分手动完成。

请在http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf上获取邮政地址标准(USPS)的副本,并注意它的长度超过130页。要实现的正则表达式会很麻烦。

对于国际地址,所有赌注都不可用。美国的工人将无法验证。

或者,使用数据服务。但是,我没有任何建议。

此外:当我们确实发送邮件中的内容时(这是对的,对吗?),请确保将"请求的地址更正"放在信封上(在正确的位置)并更新数据库。 (我们为前台人员创建了一个简单的gui来执行此操作;该人员实际上是对邮件进行排序的人)

最后,清理数据后,查找重复项。

回答

如果是人工输入的数据,那么我们将花费太多时间尝试围绕异常进行编码。

尝试:

  • 正则表达式以提取邮政编码
  • 邮政编码查找(通过适当的政府数据库)以获取正确的地址
  • 获取实习生以手动验证新数据是否与旧数据匹配

回答

This won't solve your problem, but if
  you only needed lat/long data for
  these addresses, the Google Maps API
  will parse non-formatted addresses
  pretty well.

好的建议,或者我们可以对Google地图的每个地址执行一个CURL请求,它将返回格式正确的地址。由此,我们可以正则表达式满足内心需求。

回答

我已经在地址处理领域工作了大约5年,而且确实没有万灵丹。正确的解决方案将取决于数据的值。如果它不是很有价值,请按照其他答案的建议将其放入解析器。如果它甚至有价值,那么我们肯定需要人工评估/纠正解析器的所有结果。如果我们正在寻找一个完全自动化的,可重复的解决方案,则可能需要与Group1或者Trillium之类的地址更正供应商联系。

回答

根据这里的建议,我在VB中设计了以下功能,该功能创建可通过的数据,尽管并不总是完美的(如果给出了公司名称和套房名称,它将套房和城市结合在一起)。如果违反我自己的规则之一,请随时对我发表评论/重构/大喊大叫:

Public Function parseAddress(ByVal input As String) As Collection
    input = input.Replace(",", "")
    input = input.Replace("  ", " ")
    Dim splitString() As String = Split(input)
    Dim streetMarker() As String = New String() {"street", "st", "st.", "avenue", "ave", "ave.", "blvd", "blvd.", "highway", "hwy", "hwy.", "box", "road", "rd", "rd.", "lane", "ln", "ln.", "circle", "circ", "circ.", "court", "ct", "ct."}
    Dim address1 As String
    Dim address2 As String = ""
    Dim city As String
    Dim state As String
    Dim zip As String
    Dim streetMarkerIndex As Integer

    zip = splitString(splitString.Length - 1).ToString()
    state = splitString(splitString.Length - 2).ToString()
    streetMarkerIndex = getLastIndexOf(splitString, streetMarker) + 1
    Dim sb As New StringBuilder

    For counter As Integer = streetMarkerIndex To splitString.Length - 3
        sb.Append(splitString(counter) + " ")
    Next counter
    city = RTrim(sb.ToString())
    Dim addressIndex As Integer = 0

    For counter As Integer = 0 To streetMarkerIndex
        If IsNumeric(splitString(counter)) _
            Or splitString(counter).ToString.ToLower = "po" _
            Or splitString(counter).ToString().ToLower().Replace(".", "") = "po" Then
                addressIndex = counter
            Exit For
        End If
    Next counter

    sb = New StringBuilder
    For counter As Integer = addressIndex To streetMarkerIndex - 1
        sb.Append(splitString(counter) + " ")
    Next counter

    address1 = RTrim(sb.ToString())

    sb = New StringBuilder

    If addressIndex = 0 Then
        If splitString(splitString.Length - 2).ToString() <> splitString(streetMarkerIndex + 1) Then
            For counter As Integer = streetMarkerIndex To splitString.Length - 2
                sb.Append(splitString(counter) + " ")
            Next counter
        End If
    Else
        For counter As Integer = 0 To addressIndex - 1
            sb.Append(splitString(counter) + " ")
        Next counter
    End If
    address2 = RTrim(sb.ToString())

    Dim output As New Collection
    output.Add(address1, "Address1")
    output.Add(address2, "Address2")
    output.Add(city, "City")
    output.Add(state, "State")
    output.Add(zip, "Zip")
    Return output
End Function

Private Function getLastIndexOf(ByVal sArray As String(), ByVal checkArray As String()) As Integer
    Dim sourceIndex As Integer = 0
    Dim outputIndex As Integer = 0
    For Each item As String In checkArray
        For Each source As String In sArray
            If source.ToLower = item.ToLower Then
                outputIndex = sourceIndex
                If item.ToLower = "box" Then
                    outputIndex = outputIndex + 1
                End If
            End If
            sourceIndex = sourceIndex + 1
        Next
        sourceIndex = 0
    Next
    Return outputIndex
End Function

传递" parseAddress"函数" A. P. Croll&Son 2299 Lewes-Georgetown Hwy,乔治敦,DE 19947"返回:

2299 Lewes-Georgetown Hwy
A. P. Croll & Son  
Georgetown
DE
19947

回答

我认为外包问题是最好的选择:将其发送给Google(或者Yahoo)地理编码器。地理编码器不仅返回纬度/经度(此处不感兴趣),还返回地址的丰富解析,并填写我们未发送的字段(包括ZIP + 4和County)。

例如,解析" 1600 Amphitheatre Parkway,Mountain View,CA"的结果是

{
  "name": "1600 Amphitheatre Parkway, Mountain View, CA, USA",
  "Status": {
    "code": 200,
    "request": "geocode"
  },
  "Placemark": [
    {
      "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
      "AddressDetails": {
        "Country": {
          "CountryNameCode": "US",
          "AdministrativeArea": {
            "AdministrativeAreaName": "CA",
            "SubAdministrativeArea": {
              "SubAdministrativeAreaName": "Santa Clara",
              "Locality": {
                "LocalityName": "Mountain View",
                "Thoroughfare": {
                  "ThoroughfareName": "1600 Amphitheatre Pkwy"
                },
                "PostalCode": {
                  "PostalCodeNumber": "94043"
                }
              }
            }
          }
        },
        "Accuracy": 8
      },
      "Point": {
        "coordinates": [-122.083739, 37.423021, 0]
      }
    }
  ]
}

现在可以解析了!

回答

RecogniContact是解析美国和欧洲地址的Windows COM对象。你可以试穿
http://www.loquisoft.com/index.php?page=8

回答

请尝试www.address-parser.com。我们使用他们的网络服务,我们可以在线对其进行测试

回答

对James A. Rosen提出的解决方案+1,因为它对我来说效果很好,但是对于计算机撰写者来说,该网站是一本引人入胜的书,也是我在记录全球地址时所见到的最佳尝试:http://www.columbia.edu/kermit /postal.html

回答

我不知道这将是多么可行,但是我没有看到它被提及,所以我想我会建议这一点:

如果我们严格在美国...获取一个包含所有邮政编码,州,城市和街道的庞大数据库。现在,在地址中查找这些地址。我们可以通过测试例如所找到的城市是否在所找到的州中,或者通过检查所找到的街道是否在所找到的城市中来验证所找到的内容。如果不是这样,约翰很有可能不在约翰的大街上,而是收件人的名字……基本上,请获取尽可能多的信息,并对照该信息检查地址。
一个极端的例子是获取A中所有美国地址的列表,然后找出与每个地址最相关的地址。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。