【问题标题】:get city, state or zip from a string in python从python中的字符串获取城市、州或邮编
【发布时间】:2010-01-13 04:32:15
【问题描述】:

我希望能够从 python 中的字符串中解析出城市、州或邮政编码。所以,如果我输入了

科罗拉多州博尔德
80303
科罗拉多州博尔德
博尔德,Co 80303
...

它们的任何变体都会返回城市、州或邮编。

这都是用户输入的数据并输入到一个文本字段中。

【问题讨论】:

  • 而且只有美国地址,对吧? (hho1/2k)
  • “在一个文本字段中输入”:错误的方式,返回

标签: python regex string


【解决方案1】:

只需询问他们的邮政编码,然后使用地理编码数据库提供适用城市的(简短)列表。这样您就可以获得干净整洁的 5 位输入,它们可以节省时间,而且你们都可以愉快地回家了。

如果您已经有数据,只需查找 zip,找到可能的城市列表(只有一个适用的州),然后将所有内容都小写后匹配城市名称。

【讨论】:

  • 这可能不是一个 GUI 应用程序——它也可能是一个批处理。
  • @Jim 因此是第二段。
  • 我不想只问邮编。不是每个人都知道伊利诺伊州芝加哥或加利福尼亚州洛杉矶的邮政编码,但他们可能想搜索这些地方。
  • 啊,这完全合理 - 与我从您的问题中猜到的情况不同。
【解决方案2】:

您可以使用地理编码网络服务或类似的东西。例如,在Yahoo geocoding API 页面上,它显示了如何以多种方式指定地址:

This free field lets users enter any of the following:
    city, state
    city, state, zip
    zip
    street, city, state
    street, city, state, zip
    street, zip

并且 XML 结果提供解析后的地址,例如在页面上指定的 test URL

【讨论】:

    【解决方案3】:

    我会使用([^\d]+)?(\d{5})? 作为我的正则表达式,并使用match 所以它只匹配字符串的开头。这样它就不会因输入错误而失败,并且会对预期的内容做出最好的猜测。然后您可以在“,”上拆分第一个捕获组。

    【讨论】:

    • 这适用于 zip,(\d{5} 不够吗?)但您需要针对城市/州的另一种模式。 [a-zA-Z ]+,\s*[a-zA-Z]{5} 怎么样?
    • 不,您误解了正则表达式。第一个捕获组将匹配所有非数字字符。
    • 啊,你是对的,我现在明白了,你的模式现在我想起来很整洁。
    • 任何机会你都可以举例说明如何使用它。我不擅长正则表达式。
    【解决方案4】:
    1. easy_install ngram

    2. 每行一个包含所有城市和州名的构建文件,放在 citystate.data 加利福尼亚州红木城 弗吉尼亚州红木 等等

    3. 实验(0.2门槛有点松)


    import string
    import ngram
    cityStateParser = ngram.NGram(
      items = (line.strip() for line in open('citystate.data')) ,
      N=3, iconv=string.lower, qconv=string.lower,  threshold=.2
    )
    

    示例

    cityStateParser.search('redwood')
    [('Redwood VA', 0.5),
    ('Redwood NY', 0.5),
    ('Redwood MS', 0.5),
    ('Redwood City CA', 0.36842105263157893),
    ...
    ]
    

    注意事项: 因为这些是 NGram,所以当州是城市中 ngram 的一部分时,您可能会被淘汰 即搜索“washington”会产生比“Washington OK”得分更高的 Washington IN

    您可能还想阅读Using Superimposed Coding Of N-Gram Lists For Efficient Inexact Matching(PDF 下载)

    【讨论】:

      【解决方案5】:

      这段代码似乎做你想做的事:

      text = """
      Boulder, Co
      80303
      Boulder, Colorado
      Boulder, Co 80303
      """
      
      lines = text.splitlines()
      
      ABBREV = dict(co="Colorado", ca="California")
      STATES = ABBREV.values()
      
      def parse_addr(line):
          addr = {}
          # normalize commas
          parts = line.replace(",", " ").split()
          for part in parts:
              if part.capitalize() in STATES:
                  addr["state"] = part
              elif part.lower() in ABBREV:
                  addr["state"] = ABBREV[part.lower()]
              else:
                  try:
                      zip = int(part)
                      addr["zip"] = part
                  except ValueError:
                      addr["city"] = part
          return addr
      
      for line in lines:
          print line, parse_addr(line)
      

      输出:

      Boulder, Co {'city': 'Boulder', 'state': 'Colorado'}
      80303 {'zip': '80303'}
      Boulder, Colorado {'city': 'Boulder', 'state': 'Colorado'}
      Boulder, Co 80303 {'city': 'Boulder', 'state': 'Colorado', 'zip': '80303'}
      

      处理“南达科他州”和其他两个词的州/城市留给读者作为练习:)

      正如其他海报所建议的那样,您也可以变得聪明并使用邮政编码来缩小城市/州的范围。

      【讨论】:

      • 有很多方法可以解决这个问题。例如,如果城市名称中有一个或多个空格,则此代码将忽略除最后一部分之外的所有内容。此外,如果邮政编码格式错误以至于无法表示为 int,它将覆盖城市。
      • @danben -- 当然它很容易坏掉。一个真正强大的地址解析器本身就是一个完整的程序——而且仅适用于美国地址!
      • 每个美国地址也有一个 zip+4 地址,所有这些在这个 sn-p 中都会失败。此代码示例确实适用于给定的特定示例数据。这不是一个好的通用解决方案。
      • 就像我说的,一个通用的解决方案本身就是一个完整的应用程序。这不是您可以在 SO 上发布的代码 sn-p。您可以使用快速而肮脏的方式来解析半脏数据,或者您可以使用众多应用程序之一以正确的方式进行。在这种情况下,大量的正则表达式是通往疯狂的道路。
      猜你喜欢
      • 2013-04-05
      • 1970-01-01
      • 1970-01-01
      • 2015-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多