[英]Extract Address from String in PHP with RegEx
我試圖在美國眾議院網站上搜尋各個鏈接,以查找所有列出的個人的華盛頓地址。 問題在於華盛頓地址的格式不時變化。 有時會有子彈,煙斗,新線和破折號,很難匹配。
我正在嘗試抓取許多頁面以檢索基本相似的地址:
忽略特殊的空格。 只是為了顯示字符串部分的相似性
1433 Longworth House Office Building Washington, D.C. 20515 332 Cannon HOB Washington DC 20515 1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON, DC 20515 1238 Cannon H.O.B. (line return) Washington, DC 20515 8293 Longworth House Office Building • Washington DC • 20515 8293 Longworth House Office Building | Washington DC | 20515
這些中的每一個將單獨返回,並被成噸的其他文本和html標簽包圍。 這些地址甚至可能在地址本身中包含<br>或<br/>。
我想做的是從源字符串中捕獲第一個匹配項,並將其設置為變量的值。 根據我的理解,最好使用正則表達式來解決。
在了解了這些天可能出現的各種方式之后,我決定最好用不太嚴格的表達方式。 這些地址顯示有項目符號,豎線和換行符。 傳達以下內容的表達式也許是最好的:
[數字] [任何] [“華盛頓”] [任何] [DC | DC] [任何] [五個數字]
顯然那太松了。 當我僅對允許包含任何字符的字符感興趣時, 任何內容塊都會引入段落。
到目前為止,我未能匹配以下內容(這些只是其中的一部分)
編輯 :似乎在第一組數字和“華盛頓”之間的[任何數據]必須稍微受限一些才能正常工作。 [anything]節不應包含任何數字,因為數字是我們用來界定地址之一開頭的數字。 這適用於您提供給我們的三個網站。
我說最好的第一步是剝離所有HTML標記並替換''字符實體:
$input = strip_tags($input);
$input = preg_replace("/ /"," ",$input);
然后,如果地址匹配(接近)您指定的格式,請執行以下操作:
$results= array();
preg_match("/[0-9]+\s+[^0-9]*?\s+washington,?\s*D\.?C\.?[^0-9]+[0-9]{5}/si",$input,$results);
foreach($result[0] as $addr){
echo "$addr<br/>";
}
這適用於您提供的三個示例, $results[0]
應該包含找到的每個地址。
但是,例如,如果地址中包含“ 2號公寓”之類的地址,這將不起作用,因為它假定最接近“華盛頓特區”的數字標記了地址的開頭。
以下腳本匹配每個測試用例:
<?php
$input = "
1433 Longworth House Office Building Washington, D.C. 20515
332 Cannon HOB Washington DC 20515
1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON, DC 20515
1238 Cannon H.O.B.
Washington, DC 20515
8293 Longworth House Office Building • Washington DC • 20515
8293 Longworth House Office Building | Washington DC | 20515
";
$input = strip_tags($input);
$input = preg_replace("/ /"," ",$input);
$results= array();
preg_match_all("/[0-9]+\s+[^0-9]*?washington,?\s*D\.?C\.?[^0-9]*?[0-9]{5}/si",$input,$results);
foreach($results[0] as $addr){
echo "$addr<br/>";
}
有一些工具和API可以做到這一點。 例如, SmartyStreets的LiveAddress效果很好 。 我幫助開發了它,所以讓您感到有些痛苦...這是您在問題中提供的示例的輸出:
這是CSV輸出:
ID,Start,End,Segment,Verified,Candidate,Firm,FirstLine,SecondLine,LastLine,City,State,ZIPCode,County,DpvFootnotes,DeliveryPointBarcode,Active,Vacant,CMRA,MatchCode,Latitude,Longitude,Precision,RDI,RecordType,BuildingDefaultIndicator,CongressionalDistrict,Footnotes
1,4,69,"1433 Longworth House Office Building Washington, D.C. 20515",Y,0,,1433 Longworth House Office Building Washington D,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001330,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
2,75,134,332 Cannon HOB Washington DC 20515,Y,0,,332 Cannon Hob,,Washington DC 20515-3226,Washington,DC,20515,District of Columbia,AAU1,205153226996,,,,Y,38.89106,-77.01132,Zip5,Residential,H,Y,AL,H#Q#
3,139,199,"1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON, DC 20515",Y,0,,1641 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001411,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
4,204,247,"1238 Cannon H.O.B.
Washington, DC 20515",Y,0,,1238 Cannon H O B,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001385,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
5,252,316,8293 Longworth House Office Building • Washington DC • 20515,Y,0,,8293 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001934,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
6,321,381,8293 Longworth House Office Building | Washington DC | 20515,Y,0,,8293 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001934,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
花了大約2秒鍾。 該API在一定程度上是免費的,可能還會有其他類似的API。 我鼓勵您環顧四周,以找到最適合您的選項...我保證,這比編寫您自己的正則表達式要好(提示:其代碼背后的代碼並非基於正則表達式)。
此正則表達式對輸入字符串可以包含的內容采取更靈活的方法。 “華盛頓特區”部分尚未硬編碼到其中。 地址的不同部分分別捕獲,整個地址將在$matches[0]
捕獲。
$input = strip_tags($input);
preg_match('/
(\d++) # Number (one or more digits) -> $matches[1]
\s++ # Whitespace
([^,]++), # Building + City (everything up until a comma) -> $matches[2]
\s++ # Whitespace
(\S++) # "DC" part (anything but whitespace) -> $matches[3]
\s++ # Whitespace
(\d++) # Number (one or more digits) -> $matches[4]
/x', $input, $matches);
編輯:
在查看了您提到的站點之后,我認為以下方法應該可行。 假設您具有在名為$page
的變量中爬網的頁面內容,則可以使用
$subject = strip_tags($page)
從頁面中刪除所有HTML標記; 然后應用正則表達式
(\d+)\s*(.*?)\s*washington.{0,5}(DC|D.C.).{0,5}(\d{5})
RegexBuddy為此生成以下代碼(我不知道PHP):
if (preg_match('/(\d+)\s*(.*?)\s*washington.{0,5}(DC|D.C.).{0,5}(\d{5})/si', $subject, $regs)) {
$result = $regs[0];
} else {
$result = "";
}
$regs[1]
然后將包含第一個捕獲括號(數字)的內容,依此類推。
注意使用/si
修飾符使點與換行符匹配,並使正則表達式不區分大小寫。
您的問題對我來說不是很清楚,但是如果我對您的理解正確,我想您可以使用DOM解析器來匹配p標簽,然后檢查其中是否有單詞“ Washington”或電話號碼是否與Washington匹配區域。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.