preg match — извлечение города и почтового индекса из строки в переполнении стека

Мне нужен быстрый общий способ в PHP для извлечения информации о городе и почтовом индексе (при наличии) из входной строки.

Строка может иметь следующие формы

  1. $ input_str = «123 Main Street, Нью-Хейвен, Коннектикут»;
  2. $ input_str = «123 Main Street, Нью-Хейвен, CT 06510»;
  3. $ input_str = «Нью-Хейвен, Коннектикут, США»;
  4. $ input_str = «Нью-Хейвен, CT 06510»;

Я думал, что для (1) & (3) по крайней мере я мог бы взорвать входную строку с помощью «,», а затем выполнить цикл по массиву, чтобы найти 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

Решение

Я не самый лучший с регулярным выражением, но вот пример того, как найти двухсимвольное состояние с почтовым индексом или без него.

Regex: (([A-Z]{2})|[0-9]{5})+

скрипка

Тем не менее, если вы хотите сопоставлять только тогда, когда состояние и почтовый индекс вместе, взгляните на это:
Regex: (([A-Z]{2})(\s*[0-9]{5}))+

скрипка

Надеюсь это немного поможет.

РЕДАКТИРОВАТЬ

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 Australiaforeach($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
)

Обратите внимание, что этот класс может быть значительно оптимизирован и улучшен. Это то, что я придумал в течение часа, поэтому я не могу гарантировать, что он будет работать для всех типов входов. По сути, вы должны убедиться, что пользователь, по крайней мере, старается использовать запятые для разделения частей адреса. Вы также хотите убедиться в том, что указано прописное состояние и действительный пятизначный почтовый индекс.

Несколько правил

  1. Чтобы извлечь почтовый индекс, необходимо предоставить действительное двухсимвольное состояние с действительным почтовым индексом рядом с ним. Пример: CT 06510. Без состояния просто ввод пяти цифр не имеет смысла, поскольку в номере улицы также может быть пять цифр. (Не может различить два).

  2. Улица и номер могут быть извлечены только в том случае, если в последовательности есть число и слово (а). Пример: 123 Main Street, Он также должен быть разделен запятой, или он будет захватывать все слова после числа. Например, 123 Main Street New Haven, CT 06518Код будет тот что улица и номер 123 Main Street New Haven скорее, чем 123 Main Street,

  3. Простой ввод пятизначного почтового индекса не сработает.

  4. Если страна не указана, она будет угадывать страну при условии наличия действующего почтового индекса (см. Список почтовых индексов и их соответствующих стран выше).

  5. Предполагается, что дефисы предоставляться не будут (особенно для названий городов). Это может быть изменено позже. (Регулярное выражение необходимо изменить, чтобы приспособить переносимые слова к названиям городов и улиц). (фиксированный)

  6. Суть в том, что вы можете сделать намного больше, если у вас есть время, чтобы изменить и изменить регулярные выражения и настроить их соответствующим образом.

Я настоятельно рекомендую вам использовать формы (в случае, если у вас их еще нет), чтобы легко фиксировать адрес, указанный во входных данных. Это, вероятно, сделает вашу жизнь намного проще.

Быстрое использование

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]