Hi All,
After years of choosing is_int, is_numeric and preg_match to figure out if something is really a number I just took an hour and wrote a "soup to nuts" function called parse_number() - use it if you can, but please suggest approaches to it. Returns blank if the value is NOT a number, or an array of the parts if it is.
A sample can be found at
http://license.relatebase.com/client/admin/create_fromdata/temp350.php
all of these numbers wuld be accepted:
1
1.5
-1.5
+1.5
+.5
29482948.29482
+29482948.29482
.00008
1,358,294 [but there can be no white space on either side of the comma]
1.2859E10
1.2859E+10
1.2859exp10
1.2859exp-10
1.2859x1010
1.2859 x 10-10
it returns more than you probably want to know about the number, unless you're doing scientific work or want to analyze data in an import file for creating field types, making sure the field can hold all the values.
Here is the function - feedback is greatly appreciated
function parse_number($n){
function parse_number($n){
/****
2005-12-17:
WARNING!!!! At least on my Linux 8 server it looks like I'm only getting 14 digits to show (integer and decimal portion combined) for both + and - numbers. However I'm not sure how much more the returned value stores internally. Best way to check is to take two numbers and have one have more decimal places (otherwise identical) and subtract, then shift decimal point - not tested as of today.
To-do: doesn't deal with cent or $ currency signs and should
also doesn't deal with ordinals such as 1st, 2nd, 3rd, etc.
****/
//presume separator is a , and decimal is a .
//returns sign, integer_part, decimal_part, exponential_sign, exponential_part, and type
$n=strtolower(trim($n));
if(preg_match('/(\s,)|(,\s)/',$n))return; //, OK for separator but must be tight to #'s on both sides
$n=strtolower(str_replace(',','',trim($n)));
preg_match('/^(\+|-)*\s{0,3}([0-9]+)*(\.([0-9]+))*(\s*(e|exp|(\s{0,3}x\s{0,2}10\s{0,2}\^))\s*(\+|-)*([0-9]+))*$/i',$n,$a);
//echo "<pre>";
//print_r($a);
if(!$a[2] && !$a[4]) return;
$b['sign']=($a[1]=='-'?$a[1]:''); //return no sign if positive
if($a[2]) $ip=$b['int_part']=$a[2];
if($a[4]) $dp=$b['dec_part']=$a[4];
if($a[9]) $es=$b['exponential_sign']=($a[8]=='-'?'-':'');
if($a[9]) $ep=$b['exponential_part']=$a[9];
$t=$b['type']=
( strlen($ep) ? 'exponential' : (strlen($dp) ? 'decimal' : 'integer') );
//values such as 105.75Exp00 could really be considered as decimal or int
//values such as 105.00 could really be considered as int
$b['true_type']=
( !strlen(str_replace('0','',$ep)) ? (!strlen(str_replace('0','',$dp)) ? 'integer' : 'decimal' ) : 'exponential');
if($dp)$_dp=$dp/pow(10,strlen($dp));
$ep ? eval( '$pw=pow(10,'.($es ? '-' : '').$ep.');' ) : $pw=1;
$b['value']= (($b['sign'] ? -1 : 1) * ($ip + $_dp)) * $pw;
return $b;
}