2012-06-22 64 views
95

我們做業務主要是在美國,並試圖通過所有地址字段組合成一個單一的文本區域,以改善用戶體驗。但也有一些問題:如何解析自由街/郵寄地址出來的文字,併爲組件

  • 地址的用戶類型可能不正確或標準格式
  • 地址必須被分成幾部分(街道,城市,國家等)來處理信用卡信用卡支付
  • 用戶可以進入的不僅僅是他們的地址多(如他們的名字或公司與它)
  • 谷歌能做到這一點,但服務的條款和查詢的限制是望而卻步,尤其是在預算緊張的

顯然,這是一個常見的問題:

有沒有辦法將一個地址與它周圍的文本隔離開來並將其分成幾塊?有沒有一個正則表達式來解析地址?

回答

219

我看到了這個問題,很多時候我曾在一個地址驗證公司。我在這裏發佈答案,以便使用相同問題搜索周圍的程序員更容易訪問。我所在的公司處理了數十億個地址,我們在這個過程中學到了很多東西。

首先,我們需要了解有關地址的幾件事情。

地址不能regular

這意味着正則表達式都出來了。我已經看到了這一切,在一個非常特殊的格式相匹配的地址是簡單的正則表達式,這?!

/\ s +(\ d {2,5} \ S +)([A | P ]米\ b)中(([A-ZA-Z | \ S +] {1,5}){1,2})([\ S |?\,|?] +)(([A-ZA- ž| \ S +] {1,30}){1,4})(法院| CT |街道| ST |驅動器|博士|車道| LN |公路| RD | BLVD)([\ S | \ |。| \;??] +)(([A-ZA-Z | \ S +] {1,30}){1,2})([\ S | \,|] +)\ b(AK | AL | AR | AZ | CA | CO | CT | DC | DE | FL | GA | GU | HI | IA | ID | IL | IN | KS | KY | LA | MA | MD | ME | MI | MN | MO | MS | MT | NC | ND | NE | NH | NJ | NM | NV | NY | OH |行|或| PA | RI | SC | SD | TN | TX | UT | VA | VI | VT | WA | WI | WV | WY)([\ S | \,|。]?+)(\ S + \ d {5})([\ S | \,|。] +)/ I

...到this一個900多行的線文件生成一個超大規模的正則表達式,用於匹配甚至更多。我不建議這樣做(例如,here's a fiddle of the above regex, that makes plenty of mistakes)。沒有一個簡單的魔法公式可以使這個工作。在通過理論理論和,它不可能用一個正則表達式匹配的地址。

USPS Publication 28文檔,這些文檔可能的地址的多種格式,他們所有的關鍵字和variatons。最糟糕的是,地址往往含糊不清。單詞可能意味着不止一個東西(「聖」可以是「聖」或「街」),並且有我敢肯定他們發明的單詞。 (誰知道「Stravenue」是一個街道後綴?)

你需要一些真正瞭解地址的代碼,如果該代碼確實存在,這是一個商業祕密。但如果你真的瞭解了這一點,你可能會推出自己的產品。

地址進來意想不到的形狀和大小

這裏有一些人爲的(但完整)地址:

1) 102 main street 
    Anytown, state 

2) 400n 600e #2, 52173 

3) p.o. #104 60203 

即使這些都可能是有效的:

4) 829 LKSDFJlkjsdflkjsdljf Bkpw 12345 

5) 205 1105 14 90210 

顯然,這些都不是標準化。標點符號和換行符不保證。這裏是發生了什麼:

  1. 1號完成,因爲它包含一個街道地址,一個城市和國家。有了這些信息,就足以識別地址,並且可以將其視爲「可交付」(有一些標準化)。

  2. 數2是完整,因爲它也包含一個街道地址(與輔助/單元數量)和一個5位郵政編碼,這足以識別一個地址。

  3. 3號是一個完整的郵局框格式,因爲它包含一個郵政編碼。

  4. 編號4也是完整的,因爲the ZIP code is unique,這意味着私人實體或公司已經購買了該地址空間。獨特的郵政編碼適用於大批量或集中配送空間。任何寫給郵政編碼12345的東西都發往紐約斯克內克塔迪的通用電氣公司。這個例子不會特別到達任何人,但USPS仍然能夠提供它。

  5. 5號碼也是完整的,信不信由你。僅使用這些數字,可以在針對所有可能地址的數據庫進行分析時發現完整地址。當您將每個數字視爲一個組件時,填寫缺少的方向,輔助指示符和ZIP + 4代碼都是微不足道的。這裏是什麼樣子,完全展開和標準化:

205ñ1105W¯¯公寓14克

比佛利山莊CA 90210-5221

地址數據,而不是你自己

在向許可供應商提供官方地址數據的大多數國家中,地址數據本身屬於管理機構。在美國,USPS擁有這些地址。加拿大郵政,皇家郵政和其他國家也是如此,儘管每個國家都以不同的方式強制或定義所有權。知道這一點很重要,因爲它通常禁止對地址數據庫進行反向工程。您必須小心如何獲取,存儲和使用數據。

谷歌地圖是快速地址修復的常用指南,但TOS是相當禁止的;例如,您不能在不顯示Google Map的情況下使用他們的數據或API,並且僅用於非商業目的(除非您支付費用),並且您不能存儲數據(臨時緩存除外)。說得通。 Google的數據是世界上最好的。不過,谷歌地圖確實不是驗證地址。如果一個地址不存在,它仍然會顯示地址如果確實存在(在您自己的街道上嘗試;使用您知道的房屋號碼不存在)。有時候這很有用,但要注意這一點。

Nominatim的usage policy也是類似的限制,特別是對於大量和商業用途而言,並且數據大部分來自免費來源,因此它沒有得到很好的維護(這是開放項目的性質) - 但是,這可能仍然適合您的需求。它得到了一個偉大的社區的支持。

USPS本身有一個API,但it goes down a lot並沒有保證也沒有支持。它可能也很難使用。有些人使用它沒有問題。但很容易錯過USPS要求您僅使用API​​來確認通過它們傳送的地址。

人們期望的地址是硬

不幸的是,我們已經調節我們的社會期望複雜地址。整個互聯網上有很多關於這方面的優秀用戶體驗文章,但事實是,如果你有一個單獨的字段的地址表單,這是用戶期望的,即使它使得難以處理不符合邊緣地址的邊緣地址表單格式期望的格式,或者表單需要它不應該的字段。或者用戶不知道在哪裏放置他們地址的某個部分。

這些天我可以繼續討論結帳表單的糟糕用戶體驗,但相反,我只是說,將地址合併到一個字段中將是一個歡迎更改 - 人們將能夠鍵入他們的地址如何看起來合適,而不是試圖弄清楚你冗長的表格。但是,這種變化將是意想不到的,用戶可能會發現它起初有點不和諧。請注意這一點。

這個痛苦的一部分可以通過在地址之前放置國家字段來緩解。當他們首先填寫國家/地區時,您就知道如何讓您的表單出現。也許你有一個很好的方法來處理單場美國地址,所以如果他們選擇美國,你可以減少你的表單到單個字段,否則顯示組件字段。只需要考慮一下!

現在我們知道爲什麼它很難;你能爲這個做什麼?

USPS通過一個名爲CASS™認證的流程授權供應商向客戶提供經過驗證的地址。這些供應商可以訪問USPS數據庫,每月更新一次。他們的軟件必須符合嚴格的標準才能獲得認證,而且他們通常不需要同意上述討論的這些限制條款。

有許多CASS認證的公司可以處理列表或具有API:Melissa Data,Experian QAS和SmartyStreets等等。

(由於「廣告」問題,我已經截斷了我的答案,這取決於您找到適合您的解決方案。)

真相:真的,夥計們,我不在這些公司工作。這不是一個廣告。

+1

南美洲(烏拉圭)地址呢? :D –

+1

@Bart我不知道支持提取烏拉圭地址的服務,對不起! – Matt

+10

@Brian - 也許是因爲用戶爲閱讀問題和答案的人提供了大量有用的信息,而不管他們是否選擇使用他的公司產品。 – Zarepheth

7

有許多街道地址解析器。他們有兩種基本口味 - 一種擁有地名和街道名稱數據庫,另一種沒有。

正則表達式街道地址解析器可以在沒有太多麻煩的情況下獲得高達約95%的成功率。然後你開始打不尋常的情況。 CPAN中的Perl,「Geo :: StreetAddress :: US」就是這麼好的。有Python和Javascript的端口,都是開源的。我有一個改進的Python版本,通過處理更多的案例,略微提高了成功率。然而,要獲得最後3%的權利,您需要數據庫來幫助消除歧義。

具有3位郵政編碼和美國州名和縮寫的數據庫是一大幫助。當解析器看到一致的郵政編碼和州名時,它可以開始鎖定格式。這對美國和英國來說效果很好。

正確的街道地址解析從結尾開始並向後工作。這就是USPS系統如何做到的。最後,地址最不明確,國名,城市名稱和郵政編碼相對容易識別。街道名稱通常可以被隔離。街道上的地點是解析最複雜的地點;你會遇到諸如「五樓」和「Staples Pavillion」之類的東西。那時數據庫是一個很大的幫助。

+0

還有CPAN模塊Lingua:​​EN :: AddressParse。雖然速度比「Geo :: StreetAddress :: US」慢,但它的成功率更高。 –

6

我已經構建了一個地址解析系統,該系統以輸入自由形式的文本並從中提取地址。我使用的數據來自openaddresses.io(在開放許可下)。
的API是在這裏: geocode.xyz(目前僅適用於西班牙)

例如:

輸入:I need a place to stay near Plaza Volateria 3 Parque de Negocios Mas Blau I El Prat de Llobregat 08820 Spain for a couple of days

輸出:

<geodata> 
    <latt>41.3189957000</latt> 
    <longt>2.0746469000</longt> 
    <standard> 
     <stnumber>3</stnumber> 
     <staddress>VOLATERIA Plaza</staddress> 
     <city>EL PRAT DE LLOBREGAT</city> 
     <prov>ES</prov> 
     <confidence>0.8</confidence> 
    </standard> 
</geodata> 

(可能有點慢;它僅在1G內存和單個CPU的Amazon Micro實例上運行。如果這對您來說太慢,請使用提供的AMI獲得您自己的服務器。)

對於美國,墨西哥和加拿大,請參閱geocoder.ca

例如:

輸入:something going on near the intersection of main and arthur kill rd new york

輸出:

<geodata> 
    <latt>40.5123510000</latt> 
    <longt>-74.2500500000</longt> 
    <AreaCode>347,718</AreaCode> 
    <TimeZone>America/New_York</TimeZone> 
    <standard> 
    <street1>main</street1> 
    <street2>arthur kill</street2> 
    <stnumber/> 
    <staddress/> 
    <city>STATEN ISLAND</city> 
    <prov>NY</prov> 
    <postal>11385</postal> 
    <confidence>0.9</confidence> 
    </standard> 
</geodata> 

您還可以檢查在網絡界面中的結果或得到輸出JSON或JSONP。例如。 I'm looking for restaurants around 123 Main Street, New York

+0

如何使用openaddress實現地址解析系統?您使用蠻力策略嗎? –

+1

「蠻力」是什麼意思?將文本轉換爲可能的地址字符串的所有可能組合,並將每一個與地址數據庫進行比較是不現實的,並且將花費更多的時間來提供比本系統更好的答案Openaddresses是構建「訓練集」的數據源之一,它使用這些信息來解析非結構化文本中的地址 –

+2

另一個類似的系統是Geo :: libpostal(http://perltricks.com/article/announcing-geo--libpostal/)它們也使用openstreetmap和openaddresses似乎,建立地址模板飛 –

0

在我們的項目中,我們使用了以下地址解析器。它精確地解析了世界上大多數國家的地址。

http://address-parser.net/

它可以作爲獨立的庫或作爲現場API。

4

libpostal:一個開源庫,用於解析地址,使用來自OpenStreetMap,OpenAddresses和OpenCage的數據進行培訓。

https://github.com/openvenues/libpostalmore info about it

其他工具/服務:

1

如果你想依靠OSM數據libpostal是非常強大的,處理了大量與地址輸入最常見的需要注意的地方。

+0

我認爲你的答案是[這篇文章。](https://stackoverflow.com/ a/45029380/241211)好的建議,但。 – Michael

相關問題