I thought I'd ask if anyone knows of a function which has been tested vs. re-inventing the horse.

Here is the deal, when I do a mysql query, of course I get an array back, but ALL of the array values are "strings" even the value from a float field. And to php it appears that:

'6.200000' == '6.2'

just as

6.200000 == 6.2

does php basically try comparisons as numbers first if possible? maybe I don't need to convert types in my arrays to clean them up then, but is there however a good function which DOES do this cleanup (converting all number candidates to numbers if possible)?

Thanks

    That's exactly what I was thinking of.. but wondered if someone could spare me an hour on programming myself 🙂

    So, I went ahead and re-invented the horse - could you guys ride my horse and see if it bucks you off and email me if you have a problem.

    Bottom line, is_numeric() is cool but I wasn't aware of a recursive function to auto-typecast an array using common sense on what user input might be - this seems to work.

    //this accepts both arrays and non-arrays
    function numeralize(&$a){
    	/* 
    	Version 0.1 created 2008-09-26 by Samuel Fullman (sam.fullman at verizon.net)
    	-----------------------------------------------------------------------------
    	* Takes an array of typical submitted data and "numeralizes" it into the proper typecasts.
    	* This does not deal with the $ sign for currency which a user might add - that would be left as a string.
    	* This also does not deal with a % - might consider a flag to turn 75% into (float) .75
    	* comment out all the echo's when you're satisfied this works
    
    If you modify the function please EMAIL ME so I can improve this!
    */
    global $leaveExponentNotationAsString;
    if(!isset($leaveExponentNotationAsString)) $leaveExponentNotationAsString=true;
    
    if(is_array($a)){
    	foreach($a as $n=>$v){
    		if(is_array($v)){
    			numeralize(&$a[$n]);
    		}else{
    			//Note how I deal with commas, a comma in a number is always followed by exactly 3 numbers - sorry to think like an American here :) - you could modify this to use a . instead
    			if(is_numeric(preg_replace('/,([0-9]{3})/','$1',$v))){
    				//make the conversion
    				$v=preg_replace('/,([0-9]{3})/','$1',$v);
    				if(substr($v,0,1)=='+'){
    					//the + is problematic from a standpoint of user data submission.  +50 could mean an entirely different thing than 50.  By some conventions, +50 could mean "add 50 to what's there" whereas 50 would mean "set the value to 50".  The - is less so since it MUST be used to denote a negative.  Because it would be extremely rare that a user input would be +.. to indicate a positive numeric value, we leave any value with a + at the front as a string
    					//default: leave as string
    					echo 'case1: ' . $v . '<br />';
    				}else if(preg_match('/e/i',$v) && $leaveExponentNotationAsString){
    					//note "172E3" might be a product number or etc that the user doesn't want converted into 172000
    					echo 'case1b: '. $v . '<br />';
    				}else if(!preg_match('/\./',$v)){
    					//integer strictest case either nnn or -nnn.  However we still first typecast as (float), NOT (int) because typecasting as (int) would lose the 'e03' if exponential part was present
    					echo 'case2: ' . $v . '<br />';
    					$a[$n]=(float)$v;
    					$a[$n]=(int)$a[$n];
    				}else{
    					//decimal by definition (possible exponential part present)
    					echo 'case3: ' . $v . '<br />';
    					$a[$n]=(float)$v;
    				}
    			}else{
    				echo 'case4: ' . $v . '<br />';
    			}
    		}
    	}
    }else{
    	//this code exactly as above - see notes there
    	if(is_numeric(preg_replace('/,([0-9]{3})/','$1',$a))){
    		$a=preg_replace('/,([0-9]{3})/','$1',$a);
    		if(substr($a,0,1)=='+'){
    			echo 'case5: ' . $a . '<br />';
    		}else if(preg_match('/e/i',$a) && $leaveExponentNotationAsString){
    			echo 'case5b: '. $a . '<br />';
    		}else if(!preg_match('/\./',$a)){
    			echo 'case6: ' . $a . '<br />';
    			$a=(float)$a;
    			$a=(int)$a;
    		}else{
    			echo 'case7: ' . $a . '<br />';
    			$a=(float)$a;
    		}
    	}else{
    		echo 'case8: ' . $a . '<br />';
    	}
    }
    }
    $a=array(
    	1=>'hello',
    	2=>'35e2',
    	3=>'35.6e2',
    	4=>array(
    		1=>'5',
    		2=>'77.3',
    		3=>'+77.33',
    		4=>'69.50000000',
    		5=>'five'
    	),
    	5=>'3,000'
    );
    numeralize($a);
    echo '<pre>';
    print_r($a);
    

      With the "==" operator, as long as both expressions can be evaluated as numbers, a numeric comparison will be performed. For example, each of the following returns true:

      <pre><?php
      var_dump(6.2 == 6.2000);
      var_dump("6.2" == 6.2000);
      var_dump(6.2 == "6.2000");
      var_dump("6.2" == "6.2000");
      ?></pre>
      

        nogdog I did find that out with some testing, but the function here is also meant to deal with user data such as 3,000 and etc. which might not be read correctly, and to clean up the type if in fact more rigorous comparisons are needed. I'm thinking on a form post, or when data is gotten from a mysql query.

        Samuel

          I'd be more inclined to handle this in the validation stage, and if the input value is not in a format you expect, then reject it with an error explaining what is acceptable. But if you want to filter it without rejecting it (and hope you are ending up with what the user intended), then you might want to look at the [man]filter_var/man function, and in particular using the FILTER_SANITIZE_NUMBER_FLOAT and FILTER_SANITIZE_NUMBER_INT filter constants.

            Write a Reply...