Tried this on twelve different lines that looked like yours, and it worked just fine:
function str_to_address($context) { $context_parts = array_reverse(explode(" ", $context)); $zipKey = ""; foreach($context_parts as $key=>$str) { if(strlen($str)===5 && is_numeric($str)) { $zipKey = $key; break; } } $context_parts_cleaned = array_slice($context_parts, $zipKey); $context_parts_normalized = array_reverse($context_parts_cleaned); $houseNumberKey = ""; foreach($context_parts_normalized as $key=>$str) { if(strlen($str)>1 && strlen($str)<6 && is_numeric($str)) { $houseNumberKey = $key; break; } } $address_parts = array_slice($context_parts_normalized, $houseNumberKey); $string = implode(' ', $address_parts); return $string; }
This implies a house number of at least two digits and no more than six. This also assumes that the zip code is not in an “extended” form (for example, 12345-6789). However, this can be easily changed to fit this format (regular expression would be a good option here, something like (\d{5}-\d{4}) .
But using regex to analyze the data entered by the user ... It is not a good idea here because we simply do not know what the user enters, because there were (as you might assume) the lack of checks.
Looking through the code and logic, starting with creating an array from the context and capturing zip:
// split the context (for example, a sentence) into an array, // so we can loop through it. // we reverse the array, as we're going to grab the zip first. // why? we KNOW the zip is 5 characters long*. $context_parts = array_reverse(explode(" ", $context)); // we're going to store the array index of the zip code for later use $zipKey = ""; // foreach iterates over an object given the params, // in this case it like doing... // for each value of $context_parts ($str), and each index ($key) foreach($context_parts as $key=>$str) { // if $str is 5 chars long, and numeric... // an incredibly lazy check for a zip code... if(strlen($str)===5 && is_numeric($str)) { $zipKey = $key; // we have what we want, so we can leave the loop with break break; } }
Make some recyclers so that we have the best object to decorate the house number with
And then let me grab the house number using the same basic logic as the zip code:
$houseNumberKey = ""; foreach($context_parts_normalized as $key=>$str) { if(strlen($str)>1 && strlen($str)<6 && is_numeric($str)) { $houseNumberKey = $key; break; } } // we probably have the parts we for the address. // let do some more cleaning $address_parts = array_slice($context_parts_normalized, $houseNumberKey); // and build the string again, from the address $string = implode(' ', $address_parts); // and return the string return $string;