I want to separate the area code from a phone number string by using a area code mysql database.
For example the string is 0349152023.
The endresult should be 03491 52023.
To get the endresult, i want to split the string and search every digit in database.
For example 0 and then 3 and then 4 and then take the last found result.
The code i have at the moment is only to prepare the phone number string for futher actions:
$phone1 = preg_replace('/[oO]/', '0', $phone-string);
$phone2 = preg_replace("/[^0-9]/", "", $phone1);
Then i use str_split to cut the string in pieces:
$searchArray = str_split($phone2);
Thanks for your help.
You may build an array containing all the area codes.
Then you may write something like this:
foreach ($area_codes as $code) {
if (substr($phone, 0, strlen($code)) == $code) {
$phone_string = substr($phone, 0, strlen($code))." ".substr($phone, strlen($code));
}
}
You can obviously add a controller in order to verify if the area code was found or not.
step 1: select all area codes from db and put them into an array $areaCodes
step 2: iterate over $areaCodes as $code and check if the phonenumber starts with $code. if it does, create a string that has a whitespace between the code and the rest of the number
$phonenumber = '0349152023';
$preparedPhonenumber = '';
foreach($areaCodes as $code){
if(str_pos($phonenumber, $code) === 0){
// phonenumber starts with areacode
$phoneWithoutCode = substr($phonenumber, strlen($code));
$preparedPhonenumber = $code.' '.$phoneWithoutCode;
break;
}
}
// if one of the areaCodes was 0349,
// the variable $preparedPhonenumber is now '0349 152023'
edit: you can shorten the amount of returned area codes from db by selecting only those that start with a certain string.
Let's assume the shortest area code in germany is 3 digits long (which i think is correct).
$threeDigits = substr($phonenumber,0,3);
$query = "SELECT * from areacodes
WHERE code like '".$threeDigits."%'
ORDER BY CHAR_LENGTH(code) DESC";
this will drastically shrink down the probable area codes array, therefore making the script faster.
edit 2: added order by clause in query so the above code will check for longer areacodes first. (the break; in the foreach loop is now obligatory!)
Hi Leonardo Gugliotti and Cashbee
i sort the areaCodes to get a better match. The php scripts works fine, but takes to long time to handle 5000 MySQL entries. Is it possible to make the foreach search directly in mySQL?
<?php
$sample_area_codes = array( '0350', '034', '034915', '03491', '0348', '0349', '03491', '034916', '034917',);
sort($sample_area_codes);
$phone_string = '0349152023';
foreach ($sample_area_codes as $code) {
$subString = substr($phone_string, 0, strlen($code));
if ($subString == $code) {
$phone = $subString." ".substr($phone_string, strlen($code));
}
}
if (!empty($phone)) {
echo $phone;
}
else {
echo "No AreaCode found.";
}
?>
Output: 034915 2023, which is correct
A single probe (assuming INDEX(area_code)):
SELECT ...
FROM AreaCodes
WHERE area_code < ?
ORDER BY area_code DESC
LIMIT 1;
(Where you bind the $phone_number as a string into the ?)
I think you'd better split your database into a tree, making a table for each digit.
So the third digit could refer to the second, the fourth to the third, and so on until you reach the maximum lenght of the prefix. The last table should include the name of the area.
Following your example, supposing that the maximum lenght of the area code was five digits, the fifth_digit_table should have at least four fields like these:
ID
IDref
Number
Name
10 records may have the same IDref, corresponding to the number "2" at the fourth position, linked to the previous "021" through the fourth_digit_table, the three_digit_table and so on; only one among these records, that with the Number field filled with "9", should have the Name "Haan"; the others, if there aren't any, should have the Name "Solingen".
I hope you will manage to speed up your script.
Related
I am using php/mysql.
I am storing comma separated 6 digit numbers in text based column of table in database.
I want to get the method to find which numbers in given range are present in my database.
My table looks like :
|id|date|commaSeperatedList|
Now as input to sql I want to give a range of number (e.g 234101-234200).
Therefore I am expecting output to be in form of :
|id|date|number|
So, far the solution I have worked on is : Use of PHP's range function.
Using that I created a string based Long Where Clause.
foreach( $words as $word) {
$word=str_pad($word, 6, '0', STR_PAD_LEFT);
$whereClause .= ' commaSeperatedList LIKE "%' . $word . '%" OR';
}
Problem with it is that : I dont get to know exactly which were the numbers that were found common .
e.g lets say List has :
109001,234122,234123,345650
I am giving the range (234101-234200)
The above statement finds all rows that contain any number in provided range . However I also want to know which exact numbers were matched. In my provided example these numbers are : 234122,234123
So, expected output should be :
|1|date|234122|
|1|date|234123|
Any help in this regard will be appreciated.
Eventually had to store data by normalization.
There are queries(Full Text Match) that were doing the work but not only they were complex but slow as well.
As for me , Its always better to store data properly in normalized format. (Its not a space/time tradeOFF).
For others in similar situation . Do some extra work on data and store it properly.
Thanks everyone for valuable answers !
Try This Code May Help You to find between range
<?php
$list = "109001,234122,234123,345650";
$from = "234101";
$to = "234200";
$list = explode(",",$list);
foreach($list as $val)
{
if($val > $from && $val < $to)
{
echo $val."<br>";
}
}
?>
I have a website (site-1) which import pages from other website (site-2).
These pages have an id number in site-2 and this number is copied to site-1 when the importing is done. So far so good.
Problem is that the id of site-2 are huge, e.g.: 32423201639, 3212450421639,... and the sistem in site-1 is no able to handle them. So I need to make these numbers smaller when the importing is done.
It is important:
to generate unique number values.
to be bigger than 3000 and smaller than 10000.
It can not use rand(). If we execute this several time the results must be the same
UPDATE: To keep in mind:
This importing is done every week, so I need to consider this: Let's say a first importing is done, and then in the second importing ONLY the first array value changes but the others remain then this one will be the only one to be changed and the other will keep the same value as in the first importing.
The first thing I thought was something like this (but the most important is missing):
$array_values_site1 = array("12345" , "123456", "1234567", "12345678", "123456789", "1234567890", "12345678901", "123456789012", "1234567890123", "12345678901234", "123456789012345", "1234567890123456");
$array_values_site2 = array();
foreach ($array_values_site1 as &$value) {
/* here I need to change the value of $value:
--- to be bigger than 3000 and smaller than 10000.
--- It can not use rand(). If we execute this several time the results must be the same
--- to be unique */
$new_value = "....";
$array_values_site2 [] = $new_value;
}
Looking at the comments, hashing the original ID appears best:
$hashids = new Hashids\Hashids('this is my salt');
$id = $hashids->encode(1);
$original = $hashids->decode($id);
To specify a minimum length (not a number, but a length) and characters to use in the result, include a second and third parameter:
$hashids = new Hashids\Hashids('this is my salt');
$id = $hashids->encode(1, 8, 'abcdefghij1234567890');
$original = $hashids->decode($id);
// $id = '514cdi42';
See hashids.org and github for info.
I have the following street names and house numbers in a text file:
Albert Dr: 4116-4230, 4510, 4513-4516
Bergundy Pl: 1300, 1340-1450
David Ln: 3400, 4918, 4928, 4825
Garfield Av: 5000, 5002, 5004, 5006, 8619-8627, 9104-9113
....
This data represents the boundary data for a local neighborhood (i.e., what houses are inside the community).
I want to make a PHP script that will take a user's input (in the form of something like "4918 David Lane" or "3000 Bergundy") search this list, and return a yes/no response whether that house exists within the boundaries.
What would be an efficient way to parse the input (regex?) and compare it to the text list?
Thanks for the help!
It's better to store this info in a database so that you don't have to parse out the data from a text file. Regexes are also not generally applicable to find a number in a range so a general purpose language is advised as well.
But... if you want to do it with regexes (and see why it's not a good idea)
To lookup the numbers for a street use
David Ln:(.*)
To then get the numbers use
[^,]*
You could simply import the file into a string. After this is done, breack each line of the file in an array so Array(Line 1=> array(), Line 2=> array(), etc. After this is done, you can explode using :. After, you'll simply need to search in the array. Not the fastest way, but it may be faster then regex.
You should sincerely consider using a database or re-think how your file are.
Try something like this, put your street names inside test.txt.. Now that you are able to get the details inside the text file, just compare it with the values that you submit in your form.
$filename = 'test.txt';
if(file_exists($filename)) {
if($handle = fopen($filename, 'r')) {
$name = array();
while(($file = fgets($handle)) !==FALSE) {
preg_match('#(.*):(.*)#', $file, $match);
$array = explode(',', $match[2]);
foreach($array as $val) {
$name[$match[1]][] = $val;
}
}
}
}
As mentioned, using a database to store street numbers that are relational to your street names would be ideal. I think a way you could implement this with your text file though is to create a a 2D array; storing the street names in the first array and the valid street numbers in their respective arrays.
Parse the file line by line in a loop. Parse the street name and store in array, then use a nested loop to parse all of the numbers (for ones in a range like 1414-1420, you can use an additional loop to get each number in the range) and build the next array in the initial street name array element. When you have your 2D array, you can do a simple nested loop to check it for a match.
I will try to make a little pseudo-code for you..
pseudocode:
$addresses = array();
$counter = 0;
$line = file->readline
while(!file->eof)
{
$addresses[$counter] = parse_street_name($line);
$numbers_array = parse_street_numbers($line);
foreach($numbers_array as $num)
$addresses[$counter][] = $num;
$line = file->readline
$counter++;
}
It's better if you store your streets in a separate table with IDs, and store numbers in separate table one row for each range or number and street id.
For example:
streets:
ID, street
-----------
1, Albert Dr
2, Bergundy Pl
3, David Ln
4, Garfield Av
...
houses:
street_id, house_min, house_max
-----------------
1, 4116, 4230
1, 4510, 4510
1, 4513, 4516
2, 1300, 1300
2, 1340, 1450
...
In the rows, where no range but one house number, you set both min and max to the same value.
You can write a script, that will parse your txt file and save all data to db. That should be as easy as several loops and explode() with different parameters and some insert queries too.
Then with first query you get street id
SELECT id FROM streets WHERE street LIKE '%[street name]%'
After that you run second query and get answer, is there such house number on that street
SELECT COUNT(*)
FROM houses
WHERE street_id = [street_id]
AND [house_num] BETWEEN house_min AND house_max
Inside [...] you put real values, dont forget to escape them to prevent sql injections...
Or you even can run just one query using JOIN.
Also you should make sure that your given house number is integer, not float.
say if I wanted to give every user that registered on my site a unique id. It seems to me that if I wanted to do this I would have to: Create a random number for the id, check to see if that id already exists in the database, if it does exist then create another random number and send yet another query to see if that exists, and so on...
This could go on for ages. Apart from having an incrementing id, is there any decent way to do this?
The best way to do this is via the auto increment function, if you really don't want to use a function like so you could use uniqid();
Basically you it generates an unique id based on milliseconds, if you put in a kinda unique prefix in the function it will generate a very unique id.
echo uniqid('prefix');
This way you won't have to check after generating an id, if it already exists or not. You can be sure it is unique.
For more information check this url http://php.net/uniqid!
First of all, I agree with the comments. It's all overhead code, and if you're using it to make it look interesting you should really reconsider your priorities.
But, if you still need it; here's a little something:
function uid() {
mt_srand((double)microtime()*1000000);
$token = mt_rand(1, mt_getrandmax());
$uid = uniqid(md5($token), true);
if($uid != false && $uid != '' && $uid != NULL) {
$out = sha1($uid);
return $out;
} else {
return false;
}
}
Basically, it does a lot of random number generating to create a token for uniqueid, and then is sha's that. Probably overhead, but you can be sure that you never generate a double uid.
Fabian.
You can use the rand() function. It will generate a random number between two.
rand(0000,9999)
It will generate a number between 0 and 9999.
To check if it already exist:
$id = rand(0000,9999);
/* CREATE YOUR MYSQL CONNECTION */
$user_list = mysql_query("SELECT * FROM users");
while ($user = mysql_fetch_array($user_list))
{
if ($id == $user['id'])
{
echo('Already exist.');
}
else
{
/* YOUR CODE */
}
}
It's the way I did it...
If you have a string of 15 numbers you are looking at up to 999 trillion, I doubt it will run for "ages" considering there's almost 7 billion people on the planet.
Does the ID need to be numeric? By switching to alphabetic characters you will get a lot more entropy. A 6 digit number is 1,000,000 posibilities, a 6 character alphanumeric string is 2,176,782,336 possibilities. Make it mixed case alphanumeric and that jumps to 15,625,000,000.
Here's how I usually generate unique strings that are as short as possible:
$chars = 'abcdefghijklmnopqrstuvwrxyzABCDEFGHIJKLMNOPQRSTUVWRXYZ0123456789';
mt_srand((double)microtime()*1000000);
$id = '';
do {
$id .= $chars[mt_rand(0, strlen($chars) - 1)];
} while (isIdTaken($id));
var_dump($id);
You have to create a lot of items with this style of id, before you'll get to more than 3 or 4 characters.
I know it's late for this answer but the easiest solution is to generate random number and sure it will be unique 100% is
$uid = uniqid().date("Ymdhhis");
I'd like to be able to use php search an array (or better yet, a column of a mysql table) for a particular string. However, my goal is for it to return the string it finds and the number of matching characters (in the right order) or some other way to see how reasonable the search results are, so then I can make use of that info to decide if I want to display the top result by default or give the user options of the top few.
I know I can do something like
$citysearch = mysql_query(" SELECT city FROM $table WHERE city LIKE '$city' ");
but I can't figure out a way to determine how accurate it is.
The goal would be:
a) find "Milwaukee" if the search term were "milwakee" or something similar.
b) if the search term were "west", return things like "West Bend" and "Westmont".
Anyone know a good way to do this?
You should check out full text searching in MySQL. Also check out Zend's port of the Apache Lucene project, Zend_Search_Lucene.
More searching led me to the Levenshtein distance and then to similar_text, which proved to be the best way to do this.
similar_text("input string", "match against this", $pct_accuracy);
compares the strings and then saves the accuracy as a variable. The Levenshtein distance determines how many delete, insert, or replace functions on a single character it would need to do to get from one string to the other, with an allowance for weighting each function differently (eg. you can make it cost more to replace a character than to delete a character). It's apparently faster but less accurate than similar_text. Other posts I've read elsewhere have mentioned that for strings of fewer than 10000 characters, there's no functional difference in speed.
I ended up using a modified version of something I found to make it work. This ends up saving the top 3 results (except in the case of an exact match).
$input = $_POST["searchcity"];
$accuracy = 0;
$runner1acc = 0;
$runner2acc = 0;
while ($cityarr = mysql_fetch_row($allcities)) {
$cityname = $cityarr[1];
$cityid = $cityarr[0];
$city = strtolower($cityname);
$diff = similar_text($input, $city, $tempacc);
// check for an exact match
if ($tempacc == '100') {
// closest word is this one (exact match)
$closest = $cityname;
$closestid = $cityid;
$accuracy = 100;
break;
}
if ($tempacc >= $accuracy) { // more accurate than current leader
$runner2 = $runner1;
$runner2id = $runner1id;
$runner2acc = $runner1acc;
$runner1 = $closest;
$runner1id = $closestid;
$runner1acc = $accuracy;
$closest = $cityname;
$closestid = $cityid;
$accuracy = $tempacc;
}
if (($tempacc < $accuracy)&&($tempacc >= $runner1acc)) { // new 2nd place
$runner2 = $runner1;
$runner2id = $runner1id;
$runner2acc = $runner1acc;
$runner1 = $cityname;
$runner1id = $cityid;
$runner1acc = $tempacc;
}
if (($tempacc < $runner1acc)&&($tempacc >= $runner2acc)) { // new 3rd place
$runner2 = $cityname;
$runner2id = $cityid;
$runner2acc = $tempacc;
}
}
echo "Input word: $input\n<BR>";
if ($accuracy == 100) {
echo "Exact match found: $closestid $closest\n";
} elseif ($accuracy > 70) { // for high accuracies, assumes that it's correct
echo "We think you meant $closestid $closest ($accuracy)\n";
} else {
echo "Did you mean:<BR>";
echo "$closestid $closest? ($accuracy)<BR>\n";
echo "$runner1id $runner1 ($runner1acc)<BR>\n";
echo "$runner2id $runner2 ($runner2acc)<BR>\n";
}
This can be very complicated, and I am not personally aware of any good 3rd party libraries although I'm sure they exist. Others may be able to suggest some canned solutions, though.
I have written something similar from scratch a few times in the past. If you go down that route, it is probably not something you'd want to do in PHP by itself as every query would involve getting all of the records and performing your calculations on them. It will almost certainly involve creating a set of index tables that meet your specifications.
For instance, you would have to come up with rules for how you imagine that "Milwaukee" could end up spelled "milwakee." My solution to this was to do vowel compression and duplication compression (not sure if these are actually search terms). So, milwaukee would be indexed as:
milwaukee
m_lw__k__
m_lw_k_
When the search query came in for "milwaukee", I would run the same process on the text input, and then run a search on the index table for:
SELECT cityId,
COUNT(*)
FROM myCityIndexTable
WHERE term IN ('milwaukee', 'm_lw__k__', 'm_lw_k_')
When the search query came in for "milwakee", I would run the same process on the text input, and then run a search on the index table for:
SELECT cityId,
COUNT(*)
FROM myCityIndexTable
WHERE term IN ('milwaukee', 'm_lw_k__', 'm_lw_k_')
In the case of Milwaukee (spelled correctly), it would return "3" for the count.
In the case of Milwakee (spelled incorrectly) ,it would return "2" for the count (since it would not match the m_lw__k__ pattern as it only had one vowel in the middle).
If you sort the results based on the count, you would end up meeting one of your rules, that "Milwaukee" would end up being sorted higher as a possible match than "Milwakee."
If you want to build this system in a generic way (as hinted by your use of $table in the query) then you'd probably need another mapping table somewhere in there to map your terms to the appropriate table.
I'm not suggesting this is the best (or even a good) way to go about this, just something I've done in the past that might prove useful to you if you plan to try and do this without a third party solution.
Most maddening result with LIKE is this one "%man" this will return all woman in file!
In case of listing perhaps a not too bad solution is to keep on shortening the searching needle. In your case a match will come up when your searching $ is as short as "milwa".