Got a varibale that holds phone number and the number have it country prefix before it and the phone number is dynamic and can be any phone number from any country.
So, I need to get the country of the phone number by matching certain characters (i.e the country prefix preceding the phone number) in the variable against the record in the DB (country prefix would be fetched into an array) holding all country prefix.
Sample:
$phoneVar = '4477809098888'; // uk - 44
$phoneVar = '15068094490'; // usa - 1
$phoneVar = '353669767954'; // ireland - 352
$phoneVar = '2348020098787'; // nigeria - 234
If the $phoneVar is assigned any phone number value, need to be able to get the country prefix out of it.
Something like this:
echo getCountryPrefix($phoneVar, $countries_prefix_array);
This would have been easy to achieve using substr
// $countryPrefix = substr($phoneVar, 0, 3);
But countries do not have the same prefix length.
Would be pleased to get help with this.
Something like this will work.
It's probably not accurate to your code, but I'm sure you can see the logic.
function findCountryCode($number, $country_codes) {
$country_codes = usort($country_codes, 'lsort');
foreach ($country_codes as $key => $val) {
if (substr($number, 0, strlen($val)) == $val)
return $key;
}
return false;
}
function lsort($a,$b) {
return strlen($b)-strlen($a);
}
Ok this is a perfect example for a state machine !
simplest way:
$prefixes = array('44' => 'UK', '1' => 'USA', '352' => 'IRELAND', '234' => 'NIGERIA');
preg_match('/^('.implode('|',array_keys($prefixes)).')/', $phoneVar, $matches);
echo $prefixes[$matches[0]];
You might find this schema useful.
The coding is straight-forward, if you maintain a map of prefix to country code.
Sort the prefixes, start at the back so 123 is tried before 1.
You can do this like following codes:
$phoneVar = '4477809098888'; // uk - 44
$county_list = array('uk' => 44, 'usa' => 1, 'ireland' => 352, 'nigeria' => 234);
foreach ($county_list as $key => $value)
{
if (preg_match('/^'.$value.'/', $phoneVar))
{
echo "Country is: ".$key;
echo "Country code: ".$value;
break;
}
}
Output
Country is: uk
Country code: 44
You can use preg_match() :
$phoneVar = "abcdef";
$pattern = '/^44/';
preg_match($pattern, $phoneVar, $matches, PREG_OFFSET_CAPTURE, 3);
print_r("UK : ".$matches);
This can mean lengthy code. But if its just 4 countries then this would serve your purpose.
Related
I'm trying to create a basic concordance script that will print the ten words before and after the value found inside an array. I did this by splitting the text into an array, identifying the position of the value, and then printing -10 and +10 with the searched value in the middle. However, this only presents the first such occurrence. I know I can find the others by using array_keys (found in positions 52, 78, 80), but I'm not quite sure how to cycle through the matches, since array_keys also results in an array. Thus, using $matches (with array_keys) in place of $location below doesn't work, since you cannot use the same operands on an array as an integer. Any suggestions? Thank you!!
<?php
$text = <<<EOD
The spread of a deadly new virus is accelerating, Chinese President Xi Jinping warned, after holding a special government meeting on the Lunar New Year public holiday.
The country is facing a "grave situation" Mr Xi told senior officials.
The coronavirus has killed at least 42 people and infected some 1,400 since its discovery in the city of Wuhan.
Meanwhile, UK-based researchers have warned of a real possibility that China will not be able to contain the virus.
Travel restrictions have come in place in several affected cities. From Sunday, private vehicles will be banned from central districts of Wuhan, the source of the outbreak.
EOD;
$new = explode(" ", $text);
$location = array_search("in", $new, FALSE);
$concordance = 10;
$top_range = $location + $concordance;
$bottom_range = $location - $concordance;
while($bottom_range <= $top_range) {
echo $new[$bottom_range] . " ";
$bottom_range++;
}
?>
You can just iterate over the values returned by array_keys, using array_slice to extract the $concordance words either side of the location and implode to put the sentence back together again:
$words = explode(' ', $text);
$concordance = 10;
$results = array();
foreach (array_keys($words, 'in') as $idx) {
$results[] = implode(' ', array_slice($words, max($idx - $concordance, 0), $concordance * 2 + 1));
}
print_r($results);
Output:
Array
(
[0] => least 42 people and infected some 1,400 since its discovery in the city of Wuhan.
Meanwhile, UK-based researchers have warned of a
[1] => not be able to contain the virus.
Travel restrictions have come in place in several affected cities. From Sunday, private vehicles will
[2] => able to contain the virus.
Travel restrictions have come in place in several affected cities. From Sunday, private vehicles will be banned
)
If you want to avoid generating similar phrases where a word occurs twice within $concordance words (e.g. indexes 1 and 2 in the above array), you can maintain a position for the end of the last match, and skip occurrences that occur in that match:
$words = explode(' ', $text);
$concordance = 10;
$results = array();
$last = 0;
foreach (array_keys($words, 'in') as $idx) {
if ($idx < $last) continue;
$results[] = implode(' ', array_slice($words, max($idx - $concordance, 0), $concordance * 2 + 1));
$last = $idx + $concordance;
}
print_r($results);
Output
Array
(
[0] => least 42 people and infected some 1,400 since its discovery in the city of Wuhan.
Meanwhile, UK-based researchers have warned of a
[1] => not be able to contain the virus.
Travel restrictions have come in place in several affected cities. From Sunday, private vehicles will
)
Demo on 3v4l.org
Try this:
<?php
$text = <<<EOD
The spread of a deadly new virus is accelerating, Chinese President Xi Jinping warned, after holding a special government meeting on the Lunar New Year public holiday.
The country is facing a "grave situation" Mr Xi told senior officials.
The coronavirus has killed at least 42 people and infected some 1,400 since its discovery in the city of Wuhan.
Meanwhile, UK-based researchers have warned of a real possibility that China will not be able to contain the virus.
Travel restrictions have come in place in several affected cities. From Sunday, private vehicles will be banned from central districts of Wuhan, the source of the outbreak.
EOD;
$words = explode(" ", $text);
$concordance = 10; // range -+
$result = []; // result array
$index = 0;
if (count($words) === 0) // be sure there is no empty array
exit;
do {
$location = array_search("in", $words, false);
if (!$location) // break loop if $location not found
break;
$count = count($words);
// check range of array indexes
$minRange = ($location - $concordance > 0) ? ($location-$concordance) : 0; // array can't have index less than 0 (shorthand if)
$maxRange = (($location + $concordance) < ($count - 1)) ? ($location+$concordance) : $count - 1; // array can't have index equal or higher than array count (shorthand if)
for ($range = $minRange; $range < $maxRange; $range++) {
$result[$index][] = $words[$range]; // group words by index
}
unset($words[$location]); // delete element which contain "in"
$words = array_values($words); // reindex array
$index++;
} while ($location); // repeat until $location exist
print_r($result); // <--- here's your results
?>
Doing this in PHP
I have users input an abbreviation for a city, that gets saved as a string, for example:
ANA
BOS
VAN
These stand for: Anaheim Boston Vancouver
I want it so that when I get the input/string, it changes the string name to it's full name.
ANA -> Anaheim
BOS -> Boston
VAN -> Vancouver
What is the best way to go about this? Thank you all, greatly appreciated.
Peut22's answer ist working, but i think it is better to store the pairs in an array to be more eaily maintainable. You could also get this array from a database or config file.
$names = array(
"ANA" => "Anaheim",
"BOS" => "Boston",
"VAN" => "Vancouver",
);
if(array_key_exists((string)$userinput, $names)) {
echo $names[$userinput];
} else {
echo "invalid";
}
update: fixed, so there is no "undefined index" - notice in case you got such a low error_reportinglevel set:
$names["ANA"] = "Anaheim";
$names["BOS"] = "Boston";
$names["VAN"] = "Vancouver";
function getFullName($input, $names)
{
//turning all input into upper case letters:
$input = strtoupper($input);
//making sure input is maximum 3 characters long:
$input = substr($input, 0, 3);
if(!array_key_exists($input, $names))
{
return "*ERROR: Unknown City Abbreviation*";
}
else
{
return $names[$input];
}
}
//usage:
$user_input = "bos";
echo getFullName($user_input, $names);
I think you would get a good result by using a switch, which returns the full name if you happend to get an abbreviation, of the full input string if the name is not recognized.
An example in pseudo code would be:
Switch string
case "ANA" : string = "Anaheim"
case "BOS" : string = "boston"
end
EDIT: if you're using php, the code would then look like :
switch ($i) {
case "ANA":
$i="anaheim"
break;
case "BOS":
$i="boston"
break;
}
I was given a task to validate a telephone number (stored in the var $number) introduced by a user in my website
$number = $_POST["telephone"];
The thing is this validation is quite complex as i must validate the number to see if it is from Portugal. i thought about validating it using all the indicators from Portugal, which are 52: (50 indicators are 3 digits long and 2 indicators are 2 digits long) Example of a number:
254872272 (254 is the indicator)
i also thought about making an array with all the indicators and then with a cycle verificate somehow if the first 2/3 digits are equal to the ones in the array.
what do you guys think? how should i solve this problem?
One way is to use regular expressions with named subpatterns:
$number = 254872272;
$ind = array( 251, 252, 254 );
preg_match( '/^(?<ind>\d{3})(?<rest>\d{6})$/', $number, $match );
if ( isset($match['ind']) && in_array( (int) $match['ind'], $ind, true ) ) {
print_r( $match );
/*
Array
(
[0] => 254872272
[ind] => 254
[1] => 254
[rest] => 872272
[2] => 872272
)
*/
}
Or you can insert indicators directly into regular expression:
preg_match( '/^(?<ind>251|252|254)(?<rest>\d{6})$/', $number, $match );
There's potential REGEX ways of "solving" this, but really, all you need is in_array() with your indicators in an array. For example:
$indicators = array('254', '072', '345');
$numbers = array(
'254872272',
'225872272',
'054872272',
'072872272',
'294872272',
'974872272',
'345872272'
);
while ($number = array_shift($numbers)) {
$indicator = substr($number, 0, 3);
if (in_array($indicator, $indicators)) {
echo "$number is indicated ($indicator).\n";
} else {
echo "$number is NOT indicated ($indicator).\n";
}
}
http://codepad.org/zesUaxF7
This gives:
254872272 is indicated (254).
225872272 is NOT indicated (225).
054872272 is NOT indicated (054).
072872272 is indicated (072).
294872272 is NOT indicated (294).
974872272 is NOT indicated (974).
345872272 is indicated (345).
Also, I use strings instead of integers on purpose, since PHP is going to interpret any numbers that begin with 0 (like 0724445555) as not having a leading zero, so you need to use a string to make sure that works correctly.
Perhaps with a regular expression?
I have not tested the following, but it should check for one of the matching indicators, followed by any 6 digits, something like:
$indicators = array('123' ,'456', '78'); // etc...
$regex = '/^(' . implode('|', $indicators) . ')[0-9]{6}$/';
if(preg_match($regex, 'your test number')) {
// Run further code...
}
There's a couple of libraries around that aim to validate as many telephone number formats as possible against the actual validation format, as defined by the relevant authorities.
They are usually based on a library by Google, and there are versions for PHP.
I've been tasked with standardizing some address information. Toward that goal, I'm breaking the address string into granular values (our address schema is very similar to Google's format).
Progress so far:
I'm using PHP, and am currently breaking out Bldg, Suite, Room#, etc... info.
It was all going great until I encountered Floors.
For the most part, the floor info is represented as "Floor 10" or "Floor 86". Nice & easy.
For everything to that point, I can simply break the string on a string ("room", "floor", etc..)
The problem:
But then I noticed something in my test dataset. There are some cases where the floor is represented more like "2nd Floor".
This made me realize that I need to prepare for a whole slew of variations for the FLOOR info.
There are options like "3rd Floor", "22nd floor", and "1ST FLOOR". Then what about spelled out variants such as "Twelfth Floor"?
Man!! This can become a mess pretty quickly.
My Goal:
I'm hoping someone knows of a library or something that already solves this problem.
In reality, though, I'd be more than happy with some good suggestions/guidance on how one might elegantly handle splitting the strings on such diverse criteria (taking care to avoid false positives such as "3rd St").
first of all, you need to have exhaustive list of all possible formats of the input and decide, how deep you'd like to go.
If you consider spelled out variants as invalid case, you may apply simple regular expressions to capture number and detect the token (room, floor ...)
I would start by reading up on regex in PHP. For example:
$floorarray = preg_split("/\sfloor\s/i", $floorstring)
Other useful functions are preg_grep, preg_match, etc
Edit: added a more complete solution.
This solution takes as an input a string describing the floor. It can be of various formats such as:
Floor 102
Floor One-hundred two
Floor One hundred and two
One-hundred second floor
102nd floor
102ND FLOOR
etc
Until I can look at an example input file, I am just guessing from your post that this will be adequate.
<?php
$errorLog = 'error-log.txt'; // a file to catalog bad entries with bad floors
// These are a few example inputs
$addressArray = array('Fifty-second Floor', 'somefloor', '54th floor', '52qd floor',
'forty forty second floor', 'five nineteen hundredth floor', 'floor fifty-sixth second ninth');
foreach ($addressArray as $id => $address) {
$floor = parseFloor($id, $address);
if ( empty($floor) ) {
error_log('Entry '.$id.' is invalid: '.$address."\n", 3, $errorLog);
} else {
echo 'Entry '.$id.' is on floor '.$floor."\n";
}
}
function parseFloor($id, $address)
{
$floorString = implode(preg_split('/(^|\s)floor($|\s)/i', $address));
if ( preg_match('/(^|^\s)(\d+)(st|nd|rd|th)*($|\s$)/i', $floorString, $matchArray) ) {
// floorString contained a valid numerical floor
$floor = $matchArray[2];
} elseif ( ($floor = word2num($floorString)) != FALSE ) { // note assignment op not comparison
// floorString contained a valid english ordinal for a floor
; // No need to do anything
} else {
// floorString did not contain a properly formed floor
$floor = FALSE;
}
return $floor;
}
function word2num( $inputString )
{
$cards = array('zero',
'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty');
$cards[30] = 'thirty'; $cards[40] = 'forty'; $cards[50] = 'fifty'; $cards[60] = 'sixty';
$cards[70] = 'seventy'; $cards[80] = 'eighty'; $cards[90] = 'ninety'; $cards[100] = 'hundred';
$ords = array('zeroth',
'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth',
'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth', 'twentieth');
$ords[30] = 'thirtieth'; $ords[40] = 'fortieth'; $ords[50] = 'fiftieth'; $ords[60] = 'sixtieth';
$ords[70] = 'seventieth'; $ords[80] = 'eightieth'; $ords[90] = 'ninetieth'; $ords[100] = 'hundredth';
// break the string at any whitespace, dash, comma, or the word 'and'
$words = preg_split( '/([\s-,](?!and\s)|\sand\s)/i', $inputString );
$sum = 0;
foreach ($words as $word) {
$word = strtolower($word);
$value = array_search($word, $ords); // try the ordinal words
if (!$value) { $value = array_search($word, $cards); } // try the cardinal words
if (!$value) {
// if temp is still false, it's not a known number word, fail and exit
return FALSE;
}
if ($value == 100) { $sum *= 100; }
else { $sum += $value; }
}
return $sum;
}
?>
In the general case, parsing words into numbers is not easy. The best thread that I could find that discusses this is here. It is not nearly as easy as the inverse problem of converting numbers into words. My solution only works for numbers <2000, and it liberally interprets poorly formed constructs rather than tossing an error. Also, it is not resilient against spelling mistakes at all. For example:
forty forty second = 82
five nineteen hundredth = 2400
fifty-sixth second ninth = 67
If you have a lot of inputs and most of them are well formed, throwing errors for spelling mistakes is not really a big deal because you can manually correct the short list of problem entries. Silently accepting bad input, however, could be a real problem depending on your application. Just something to think about when deciding if it is worth it to make the conversion code more robust.
I'm trying to print the possible words that can be formed from a phone number in php. My general strategy is to map each digit to an array of possible characters. I then iterate through each number, recursively calling the function to iterate over each possible character.
Here's what my code looks like so far, but it's not working out just yet. Any syntax corrections I can make to get it to work?
$pad = array(
array('0'), array('1'), array('abc'), array('def'), array('ghi'),
array('jkl'), array('mno'), array('pqr'), array('stuv'), array('wxyz')
);
function convertNumberToAlpha($number, $next, $alpha){
global $pad;
for($i =0; $i<count($pad[$number[$next]][0]); $i++){
$alpha[$next] = $pad[$next][0][$i];
if($i<strlen($number) -1){
convertNumberToAlpha($number, $next++, $alpha);
}else{
print_r($alpha);
}
}
}
$alpha = array();
convertNumberToAlpha('22', 0, $alpha);
How is this going to be used? This is not a job for a simple recursive algorithm such as what you have suggested, nor even an iterative approach. An average 10-digit number will yield 59,049 (3^10) possibilities, each of which will have to be evaluated against a dictionary if you want to determine actual words.
Many times, the best approach to this is to pre-compile a dictionary which maps 10-digit numbers to various words. Then, your look-up is a constant O(1) algorithm, just selecting by a 10 digit number which is mapped to an array of possible words.
In fact, pre-compiled dictionaries were the way that T9 worked, mapping dictionaries to trees with logarithmic look-up functions.
The following code should do it. Fairly straight forward: it uses recursion, each level processes one character of input, a copy of current combination is built/passed at each recursive call, recursion stops at the level where last character of input is processed.
function alphaGenerator($input, &$output, $current = "") {
static $lookup = array(
1 => "1", 2 => "abc", 3 => "def",
4 => "ghi", 5 => "jkl", 6 => "mno",
7 => "pqrs", 8 => "tuv", 9 => "wxyz",
0 => "0"
);
$digit = substr($input, 0, 1); // e.g. "4"
$other = substr($input, 1); // e.g. "3556"
$chars = str_split($lookup[$digit], 1); // e.g. "ghi"
foreach ($chars as $char) { // e.g. g, h, i
if ($other === false) { // base case
$output[] = $current . $char;
} else { // recursive case
alphaGenerator($other, $output, $current . $char);
}
}
}
$output = array();
alphaGenerator("43556", $output);
var_dump($output);
Output:
array(243) {
[0]=>string(5) "gdjjm"
[1]=>string(5) "gdjjn"
...
[133]=>string(5) "helln"
[134]=>string(5) "hello"
[135]=>string(5) "hfjjm"
...
[241]=>string(5) "iflln"
[242]=>string(5) "ifllo"
}
You should read Norvigs article on writing a spellchecker in Python http://norvig.com/spell-correct.html . Although its a spellchecker and in python not php, it is the same concept around finding words with possible variations, might give u some good ideas.