30

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135
user318466
  • 403
  • 1
  • 5
  • 9

7 Answers7

80

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
  • 445,704
  • 82
  • 492
  • 529
  • 10
    +1 for `sprintf` (I wondered why no one suggested this from the beginning ;) but then you were faster than me :-D) – Felix Kling Apr 21 '10 at 11:29
  • unicornaddict: why not use regex ? I have heard they are powerful. Are they not ? – user318466 Apr 21 '10 at 11:32
  • Awesome, didn't know `sprintf` could do that. Thanks for sharing! (Bookmarked for later upvoting, can't do that right now.) – pinkgothic Apr 21 '10 at 11:32
  • 3
    @user318466: They're powerful, but they tend to be noticably slower than pure string functions. – pinkgothic Apr 21 '10 at 11:33
  • @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 Apr 21 '10 at 11:33
  • @user318466: As Felix Kling and pinkgothic have said use regex when its a must, they tend to be resource hungry(usually). – codaddict Apr 21 '10 at 11:40
  • 2
    Works good. I choose the sprintf one and not the regex as you experts suggested. – user318466 Apr 21 '10 at 11:59
  • 7
    +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 Apr 21 '10 at 12:02
8
function formatNum($num) {
   return ((float) $num>0)?'+'.$num:$num;
}
Joe Love
  • 5,594
  • 2
  • 20
  • 32
Dal Hundal
  • 3,234
  • 16
  • 21
3
function formatNum($num) {
  $num = (int) $num; // or (float) if you'd rather
  return (($num >= 0) ? '+' : '') . $num; // implicit cast back to string
}
pinkgothic
  • 6,081
  • 3
  • 47
  • 72
  • @Wolf While it's been ten years since I last looked at this question, reviewing this briefly, I'm reasonably sure that's what this snippet does (`>= 0` tests for positive numbers, and a `+` is prepended if that was true). Can you expand on where you see an incorrect comparison operator? – pinkgothic Jan 26 '21 at 00:06
  • Reviewing it again in the context of the actual problem described in the question (which is using *positive* in the same way you do), your function does it right, provided that zero values should be treated as `sprintf` does it. Unfortunately, OP had chosen an ambiguous set of examples. So we now have two answers with different result being both right. Asking for formatting *non-negative* numbers or adding `+0` would have been better in the question but that is obviously not your fault. Since you are treating existing signs correctly, your way should be preferred to Dan's. – Wolf Jan 26 '21 at 06:46
2

The simple solution is to make use of format specifier in printf() function.

For example,

$num1=2;
$num2=-2;
printf("%+d",$num1);
echo '<br>';
printf("%+d",$num2);

gives the output

+2
-2

In your case

 function formatNum($num){
    return printf("%+d",$num);
 }
rancho
  • 145
  • 9
  • 12
1

Try this:

$fmt = new NumberFormatter('es_ES', NumberFormatter::DECIMAL);
$fmt->setTextAttribute(NumberFormatter::POSITIVE_PREFIX, '+');
$result = $fmt->format(10000);

Result will be: +10.000

Exactly works NumberFormatter::POSITIVE_SUFFIX, you will receive 10.000+

Dr.X
  • 853
  • 9
  • 15
0

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.org
  • 16,462
  • 6
  • 50
  • 83
  • 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 Apr 21 '10 at 11:45
  • 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.org Apr 21 '10 at 11:47
  • 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 Apr 21 '10 at 11:51
  • 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.org Apr 21 '10 at 14:58
  • "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 Apr 21 '10 at 16:17
  • 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.org Apr 22 '10 at 04:37
0

Ok, this is rather old and probably useless, but I think there is still some space for a slight addition. If you have the number "ready":

if($num>=0) $num='+'.(0+$num);

Or, if you are sure it's a number:

if($num>=0) $num='+'.$num;
  • This does nothing on negative numbers and just changes to string if positive.

  • Adding 0 converts to Number if it is not, and does not change the numeric type, like casting to (float) or (int). It is useless if you are sure it's a number, use the second version.

  • This is probably the quickest way

  • As a downside, you will have half results as strings and half as numbers (sprintf will make them all strings)

FrancescoMM
  • 2,845
  • 1
  • 18
  • 29