views:

254

answers:

4

I need to design a function to return negative numbers unchanged but should add a + sign at the start of the number if its already no present.

Example:

Input     Output
----------------
+1         +1
1          +1
-1         -1

It will get only numeric input.

function formatNum($num)
{
# something here..perhaps a regex?
}

This function is going to be called several times in echo/print so the quicker the better.

Update:

Thank you all for the answers. I must tell the sprintf based solution is really fast.

+16  A: 

You can use regex as:

function formatNum($num){
    return preg_replace('/^(\d+)$/',"+$1",$num);
}

But I would suggest not using regex for such a trivial thing. Its better to make use of sprintf here as:

function formatNum($num){
    return sprintf("%+d",$num);
}

From PHP Manual for sprintf:

An optional sign specifier that forces a sign (- or +) to be used on a number. By default, only the - sign is used on a number if it's negative. This specifier forces positive numbers to have the + sign attached as well, and was added in PHP 4.3.0.

codaddict
+1 for `sprintf` (I wondered why no one suggested this from the beginning ;) but then you were faster than me :-D)
Felix Kling
+1 for sprintf also
Mailslut
unicornaddict: why not use regex ? I have heard they are powerful. Are they not ?
Awesome, didn't know `sprintf` could do that. Thanks for sharing! (Bookmarked for later upvoting, can't do that right now.)
pinkgothic
@user318466: They're powerful, but they tend to be noticably slower than pure string functions.
pinkgothic
@user318466: They are, but it requires more processing power... why use some general approach if there is already a specific solution for it that is probably optimized to do so?
Felix Kling
@user318466: As Felix Kling and pinkgothic have said use regex when its a must, they tend to be resource hungry(usually).
codaddict
Works good. I choose the sprintf one and not the regex as you experts suggested.
+1 for `sprintf` which should be the first port of call for printing *formatted* strings like the question asks for. -1 for (seemingly randomly?) prefixing a good answer with a regex solution.
salathe
+3  A: 
function formatNum($num) {
   return ($num>0)?'+'.$num:$num;
}
Mailslut
If I pass +1 it return ++1 :(
Then cast to int.
Mark Tomlin
if you pass it +1, it returns +1. It returns ++1, if you have passed it '+1' as a string. Nevertheless, I prefer UnicornAddict's sprintf method.
Mailslut
+1  A: 
function formatNum($num) {
  $num = (int) $num; // or (float) if you'd rather
  return (($num >= 0) ? '+' : '') . $num; // implicit cast back to string
}
pinkgothic
+1  A: 

The sprintf solution provided by @unicornaddict is very nice and probably the most elegant way to go. Just thought I'd provide an alternative anyway. Not sure how they measure up in speed.

// Non float safe version
function formatNum($num) {
    return (abs($num) == $num ? '+' : '') . intval($num);
}

// Float safe version
function formatNum($num) {
    return 
        (abs($num) == $num ? '+' : '') 
        . (intval($num) == $num ? intval($num) : floatval($num));
}

// Float safe version, alternative
function formatNum($num) {
    return 
        (abs($num) == $num ? '+' : '') 
        // Add '1' to $num to implicitly cast it to a number
        . (is_float($num + 1) ? floatval($num) : intval($num));
} 
nikc
Or: Rather than `intval()`, just `return (((string)abs($num)) === $num) ? '+' . $num : $num;` - though that might only work reliably for integers? [I bracket paranoidly, gosh.]
pinkgothic
The problem isn't in the comparison part, but rather the return part. Edited my example, but as you mentioned, it will only work for integers. Modifying to work for floats as well would be trivial, but might just demonstrate why `sprintf` is a better choice to begin with.
nikc
Agreed about `sprintf`! I'm not sure it would be trivial to modify it to work with floats, though, the string might not represent a float that can be stored as, well, float, after all, and then casting from float back to string would yield a difference where there is none?
pinkgothic
The nice (or not, sometimes) thing about PHP is you don't need to typecast. Data is typecast automagically in context. But modifying for float would be trivial, and I just couldn't resist modifying ;-)
nikc
"Data is typecast automagically in context." Yes, but it *is* cast. And my question is whether abs("0.000000000000001") would be the same (==) as "0.000000000000001". I suppose it boils down to this: I don't trust floats. :)) I should probably just play around with this and see. (Mind you, that aside, `is_float` will always yield `false` for strings.)
pinkgothic
Floats shouldn't be trusted, you are right to be sceptic. I may be wrong, but AFAIK what shouldn't (ever!) be trusted/used (about floats) is equality comparison. Less/greater than comparison should be reliable. Also, and I may be wrong in doing so, I trust internals will be able to handle floats correctly. (One more notch on `sprintf` gun.) But for the precision you example, testing for your needs proves its importance. Especially if relying on `int` casting. (You are correct pointing out the illogical (in regard of PHP:s non-strict typing) shortcoming of `is_float`, see revised.)
nikc