2014-12-17 5 views
2

입력 문자열에서 도시 및 우편 번호 (사용 가능한 경우) 정보를 추출하려면 PHP에서 일반적인 빠른 방법이 필요합니다.PHP에서 문자열에서 도시 및 우편 번호 추출하기

문자열은 다음과 같은 형태

  1. $ input_str = "123 메인 스트리트, 뉴 헤이븐, CT"이 될 수 있습니다;
  2. $ input_str = "123 Main Street, New Haven, CT 06510";
  3. $ input_str = "New Haven, CT, United States";
  4. $ input_str = "New Haven, CT 06510"; 어레이 통해

I (1) & (3)이어야 I가 함께 입력 된 문자열을 폭발 할위한 것을 생각했다 ","다음 루프는 2 자리 STATE 문자를 찾아 내고 무시. 그러나 나는이 시점을 넘어서 붙어있다.

$search_values = explode(',' ,$input_str); 
foreach($search_values as $search) 
{ 
    $trim_search = trim($search); // Remove any trailing white spaces 

    // If the 2 digit State is provided without Zipcode, ignore it 
    if (strlen($trim_search) == 2) 
    { 
     //echo 'Ignoring State Without Zipcode: ' . $search . '<br>'; 
     continue; 
    } 

    ... 
+2

가 입력이 보장되는 빠른 사용? 일반적으로 주소는 무엇이든 보장 할 수 없습니다. 사용자가 입력 한 주소 문자열은 무엇보다도 다양한 다양성과 엣지 케이스를 가지고 있습니다. 있는 그대로 전체 문자열을 가져 와서 지오 코딩 서비스로 보내고 개별 요소를 쉽게 추출 할 수있는 구조화 된 데이터를 가져 오는 것이 더 바람직 할 수 있습니다. – David

+0

감사합니다. @David 입력 내용이 제 경우에 잘 형성됩니다. 그래서 완전히 개방 된 문제는 아닙니다. 그러나 지오 코딩 서비스에 대한 흥미로운 점을 제시합니다. – rogerb

답변

1

정규식에서 가장 큰 것은 아니지만 여기에는 우편 번호와 함께 또는없는 2 자의 상태를 찾는 장면이 있습니다.

정규식 : 당신이 국가와 우편 번호가 함께있는 경우에만 일치 할 경우 (([A-Z]{2})|[0-9]{5})+

Fiddle

그러나, 이것 좀보세요 : 정규식 : (([A-Z]{2})(\s*[0-9]{5}))+

Fiddle

희망이 조금 도움이됩니다.

이 출력해야 위의 코드에서 예제를 사용하여 편집

class Extract { 

    private $_string; 

    private $_sections = array(); 

    private $_output = array(); 

    private $_found = array(); 

    private $_original_string; 

    private $_countries = array (
     'United States', 
     'Canada', 
     'Mexico', 
     'France', 
     'Belgium', 
     'United Kingdom', 
     'Sweden', 
     'Denmark', 
     'Spain', 
     'Australia', 
     'Austria', 
     'Italy', 
     'Netherlands' 
    ); 

    private $_zipcon = array(); 

    private $ZIPREG = array(
     "United States"=>"^\d{5}([\-]?\d{4})?$", 
     "United Kingdom"=>"^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$", 
     "Germany"=>"\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b", 
     "Canada"=>"^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])\s*(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$", 
     "France"=>"^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$", 
     "Italy"=>"^(V-|I-)?[0-9]{5}$", 
     "Australia"=>"^(0[289][0-9]{2})|([1345689][0-9]{3})|(2[0-8][0-9]{2})|(290[0-9])|(291[0-4])|(7[0-4][0-9]{2})|(7[8-9][0-9]{2})$", 
     "Netherlands"=>"^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$", 
     "Spain"=>"^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$", 
     "Denmark"=>"^([D-d][K-k])?(|-)?[1-9]{1}[0-9]{3}$", 
     "Sweden"=>"^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$", 
     "Belgium"=>"^[1-9]{1}[0-9]{3}$" 
    ); // thanks to http://www.pixelenvision.com/1708/zip-postal-code-validation-regex-php-code-for-12-countries/ 

    public function __construct($string) { 

     $this->_output = array (

      "state" => "", 
      "city" => "", 
      "country" => "", 
      "zip" => "", 
      "street" =>"", 
      "number" => "" 
     ); 
     $this->_original_string = $string; 
     $this->_string = $this->normalize(trim($string)); 


     // create an array of patterns in order to extract zip code using the country list we already have 
     foreach($this->ZIPREG as $country => $pattern) { 
      $this->_zipcon[] = $pattern = preg_replace(array("/\^/","/\\$/"),array("",""), $pattern); 
     } 

     $this->init(); 

    } 

    protected function init() { 

     $this->getData(); // get data that can be found without breaking up the string. 

     $this->_sections = array_filter(explode(',', trim($this->_string))); // split each section 

     if(!empty($this->_sections)) { 
      foreach($this->_sections as $i => $d) { 
       $d = preg_replace(array("/\s+/", "/\s([?.!])/"), array(" ","$1"), $d); 
       $this->_sections[$i] = trim($this->normalize($d)); // normalize strin to have one spacing between each word 
      } 
     } else { 
      $this->_sections[] = $this->_string;  
     }  

     // try to match what's missing with has already been found 
     $notFound = $this->getNotFound(); 
     if(count($notFound)==1 && count($this->_found)>1) { 
      $found = $this->getFound(); 
      foreach($found as $string) { 
       $notFound[0] = preg_replace("/$string/i", "", $notFound[0]); 
      } 
      $this->_output["city"] = $notFound[0]; 
      $this->_found[] = $this->_output["city"]; 
      $this->remove($this->_output["city"]); 
     } 
    } 

    public function getSections() { 
     return $this->_sections; 
    } 

    protected function normalize($string) { 
     $string = preg_replace(array("/\s+/", "/\s([?.!])/"), array(" ","$1"), trim($string)); 
     return $string; 
    } 

    protected function country_from_zip($zip) { 
     $found = ""; 
     foreach($this->ZIPREG as $country => $pattern) { 
      if(preg_match ("/".$pattern."/", $zip)) { 
       $found = $country; 
       break; 
      } 
     } 
     return $found; 
    } 

    protected function getData() { 
     $container = array(); 
     // extract zip code only when present beside state, or else five digits are meaningless 

     if(preg_match ("/[A-Z]{2,}\s*(".implode('|', $this->_zipcon).")/", $this->_string)){ 
      preg_match ("/[A-Z]{2,}\s*(".implode('|', $this->_zipcon).")/", $this->_string, $container["state_zip"]); 

      $this->_output["state"] = $container["state_zip"][0]; 
      $this->_output["zip"] = $container["state_zip"][1]; 
      $this->_found[] = $this->_output["state"] . " ". $this->_output["zip"]; 
      // remove from string once found 
      $this->remove($this->_output["zip"]); 
      $this->remove($this->_output["state"]); 

      // check to see if we can find the country just by inputting zip code 
      if($this->_output["zip"]!="") { 
       $country = $this->country_from_zip($this->_output["zip"]); 
       $this->_output["country"] = $country; 
       $this->_found[] = $this->_output["country"]; 
       $this->remove($this->_output["country"]); 
      } 
     } 

     if(preg_match ("/\b([A-Z]{2,})\b/", $this->_string)) { 
      preg_match ("/\b([A-Z]{2,})\b/", $this->_string, $container["state"]); 
      $this->_output["state"] = $container["state"][0]; 
      $this->_found[] = $this->_output['state']; 
      $this->remove($this->_output["state"]); 
     } 

     // if we weren't able to find a country based on the zip code, use the one provided (if provided) 
     if($this->_output["country"] == "" && preg_match("/(". implode('|',$this->_countries) . ")/i", $this->_string)){ 
      preg_match ("/(". implode('|',$this->_countries) . ")/i", $this->_string, $container["country"]); 
      $this->_output["country"] = $container["country"][0]; 
      $this->_found[] = $this->_output['country']; 
      $this->remove($this->_output["country"]); 
     } 

     if(preg_match ("/([0-9]{1,})\s+([.\\-a-zA-Z\s*]{1,})/", $this->_string)){ 
      preg_match ("/([0-9]{1,})\s+([.\\-a-zA-Z\s*]{1,})/", $this->_string, $container["address"]); 
      $this->_output["number"] = $container["address"][1]; 
      $this->_output["street"] = $container["address"][2]; 
      $this->_found[] = $this->_output["number"] . " ". $this->_output["street"]; 
      $this->remove($this->_output["number"]); 
      $this->remove($this->_output["street"]); 
     }  


     //echo $this->_string; 
    } 

    /* remove from string in order to make it easier to find missing this */ 
    protected function remove($string, $case_sensitive = false) { 
     $s = ($case_sensitive==false ? "i" : ""); 
     $this->_string = preg_replace("/".$string."/$s", "", $this->_string); 
    } 

    public function getNotFound() { 
     return array_values(array_filter(array_diff($this->_sections, $this->_found))); 
    } 

    public function getFound() { 
     return $this->_found; 
    } 

    /* outputs a readable string with all items found */ 
    public function toString() { 
     $output = $this->getOutput(); 
     $string = "Original string: [ ".$this->_original_string.' ] ---- New string: [ '. $this->_string. ' ]<br>'; 
     foreach($output as $type => $data) { 
      $string .= "-".$type . ": " . $data. '<br>';  
     } 
     return $string; 
    } 

    /* return the final output as an array */ 
    public function getOutput() { 
     return $this->_output; 
    } 

} 



$array = array(); 
$array[0] = "123 Main Street, New Haven, CT 06518"; 
$array[1] = "123 Main Street, New Haven, CT"; 
$array[2] = "123 Main Street, New Haven,       CT 06511"; 
$array[3] = "New Haven,CT 66554, United States"; 
$array[4] = "New Haven, CT06513"; 
$array[5] = "06513"; 
$array[6] = "123 Main Street, New Haven CT 06518, united states"; 

$array[7] = "1253 McGill College, Montreal, QC H3B 2Y5"; // google Montreal/Canada 
$array[8] = "1600 Amphitheatre Parkway, Mountain View, CA 94043"; // google CA/US 
$array[9] = "20 West Kinzie St., Chicago, IL 60654"; // google IL/US 
$array[10] = "405 Rue Sainte-Catherine Est, Montreal, QC"; // Montreal address shows hyphened street names 
$array[11] = "48 Pirrama Road, Pyrmont, NSW 2009"; // google Australia 


foreach($array as $string) { 
    $a = new Extract($string); 

    echo $a->toString().'<br>'; 
} 

:

Original string: [ 123 Main Street, New Haven, CT 06518 ] ---- New string: [ , , ] 
-state: CT 
-city: New Haven 
-country: United States 
-zip: 06518 
-street: Main Street 
-number: 123 

Original string: [ 123 Main Street, New Haven, CT ] ---- New string: [ , , ] 
-state: CT 
-city: New Haven 
-country: 
-zip: 
-street: Main Street 
-number: 123 

Original string: [ 123 Main Street, New Haven, CT 06511 ] ---- New string: [ , , ] 
-state: CT 
-city: New Haven 
-country: United States 
-zip: 06511 
-street: Main Street 
-number: 123 

Original string: [ New Haven,CT 66554, United States ] ---- New string: [ , , ] 
-state: CT 
-city: New Haven 
-country: United States 
-zip: 66554 
-street: 
-number: 

Original string: [ New Haven, CT06513 ] ---- New string: [ , ] 
-state: CT 
-city: New Haven 
-country: United States 
-zip: 06513 
-street: 
-number: 

Original string: [ 06513 ] ---- New string: [ 06513 ] 
-state: 
-city: 
-country: 
-zip: 
-street: 
-number: 

Original string: [ 123 Main Street, New Haven CT 06518, united states ] ---- New string: [ , , ] 
-state: CT 
-city: New Haven 
-country: United States 
-zip: 06518 
-street: Main Street 
-number: 123 

Original string: [ 1253 McGill College, Montreal, QC H3B 2Y5 ] ---- New string: [ , , ] 
-state: QC 
-city: Montreal 
-country: Canada 
-zip: H3B 2Y5 
-street: McGill College 
-number: 1253 

Original string: [ 1600 Amphitheatre Parkway, Mountain View, CA 94043 ] ---- New string: [ , , ] 
-state: CA 
-city: Mountain View 
-country: United States 
-zip: 94043 
-street: Amphitheatre Parkway 
-number: 1600 

Original string: [ 20 West Kinzie St., Chicago, IL 60654 ] ---- New string: [ , , ] 
-state: IL 
-city: Chicago 
-country: United States 
-zip: 60654 
-street: West Kinzie St. 
-number: 20 

Original string: [ 405 Rue Sainte-Catherine Est, Montreal, QC ] ---- New string: [ , , ] 
-state: QC 
-city: Montreal 
-country: 
-zip: 
-street: Rue Sainte-Catherine Est 
-number: 405 

Original string: [ 48 Pirrama Road, Pyrmont, NSW 2009 ] ---- New string: [ , , ] 
-state: NSW 
-city: Pyrmont 
-country: Australia 
-zip: 2009 
-street: Pirrama Road 
-number: 48 

당신이 사용할 수 있도록 실제 저장된 값을 추출 할 경우

. getOutput()으로 전화해야합니다. 그러면 필요한 모든 값을 가진 배열이 반환됩니다.

Array 
(
    [state] => CT 
    [city] => New Haven 
    [country] => United States 
    [zip] => 06518 
    [street] => Main Street 
    [number] => 123 
) 

이 클래스는 크게 최적화하고 개선 할 수 있음을 유의하시기 바랍니다 : 우리는이 방법을 사용하여 우리의 목록과 출력의 값을 첫 번째 주소를 취할 경우, 출력해야한다. 이것이 내가 한 시간 안에 생각해 낸 것이므로 모든 유형의 입력에 대해 작동 할 것이라고 보장 할 수는 없습니다. 본질적으로 사용자는 최소한 주소 부분을 구분하기 위해 쉼표를 사용하는 데 최소한의 노력을해야합니다. 또한 대문자 상태가 제공되고 유효한 5 자리 우편 번호인지 확인하려고합니다.

몇 가지 규칙 우편 번호를 추출하기 위해

  1. 는 유효한 2 문자 상태는 옆에 유효한 우편 번호를 제공해야합니다. 예 : CT 06510. 상태가 없으면 거리 번호에 5 자리 숫자가있을 수 있으므로 단순히 5 자리를 입력하는 것은 의미가 없습니다. (둘 사이를 구별 할 수 없다).

  2. 숫자와 단어가 순서대로 제공되는 경우에만 거리와 숫자를 추출 할 수 있습니다. 예 : 123 Main Street. 또한 쉼표로 구분하거나 숫자 뒤에 나오는 모든 단어를 캡처합니다. 예를 들어, 123 Main Street New Haven, CT 06518, 코드는 거리와 숫자가 123 Main Street이 아닌 123 Main Street New Haven이라는 코드를 사용합니다.

  3. 단순히 5 자리 우편 번호를 입력해도 작동하지 않습니다.

  4. 국가가 지정되지 않은 경우 올바른 우편 번호가있는 국가를 추측합니다 (위의 우편 번호 및 해당 국가 목록 참조).

  5. 하이픈이 제공되지 않는다고 가정합니다 (특히 도시 이름의 경우). 나중에 수정할 수 있습니다. (정규 표현식은 도시와 거리 이름 모두에 하이픈이있는 단어를 수용 할 수 있도록 수정해야합니다). (고정)

  6. 결론은 정규 표현식을 변경하고 수정하고 이에 맞게 사용자 정의 할 수있는 시간이 많으면 많은 일을 할 수 있다는 것입니다.

입력에 제공된 주소를 쉽게 캡처하기 위해 양식을 사용하도록 강력히 권합니다 (아직 가지고 있지 않은 경우). 아마 네 인생을 훨씬 편하게 해줄거야.

잘 형성 방법

$Extract = new Extract("123 Main Street, New Haven, CT 06518"); 
$foundValues = $Extract->getOutput(); 
+0

답변 해 주셔서 감사합니다. 확실히 도움이됩니다. 그러나 완벽한 제네릭 솔루션은 여전히 ​​나를 잊어 버립니다. – rogerb

+0

@rogerb 그래서 당신이하고 싶은 것은 정확히 무엇입니까? 당신은 상태를 추출하고 zip 대처하고 변수 어딘가에 저장 하시겠습니까? – Dimitri

+0

예. 사실 그 도시와 우편 번호는 추출하고 변수에 저장합니다. 우편 번호는 항상 5 자리이지만 도시는 1 단어 (예 : 밀포드) 또는 여러 단어 (예 : 뉴 헤이븐)가 될 수 있습니다. – rogerb

관련 문제