85

Could anyone give me an explanation (and maybe an example) on how to strip the trailing zeros from a number using PHP.

For example:

"Lat":"37.422005000000000000000000000000","Lon":"-122.84095000000000000000000000000"

Would be turned in to:

"Lat":"37.422005","Lon":"-122.84095"

I am trying to strip the zeros to make it more readable. I tried using str_replace() but this replaced the zeros inside the number too.

Arnaud
  • 7,259
  • 10
  • 50
  • 71
nhunston
  • 1,347
  • 5
  • 13
  • 22

15 Answers15

150

Forget all the rtrims, and regular expressions, coordinates are floats and should be treated as floats, just prepend the variable with (float) to cast it from a string to a float:

$string = "37.422005000000000000000000000000";
echo (float)$string;

output:

37.422005

The actual result you have are floats but passed to you as strings due to the HTTP Protocol, it's good to turn them back into thier natural form to do calculations etc on.

Test case: http://codepad.org/TVb2Xyy3

Note: Regarding the comment about floating point precision in PHP, see this: https://stackoverflow.com/a/3726761/353790

Community
  • 1
  • 1
RobertPitt
  • 56,863
  • 21
  • 114
  • 161
  • a good point, would make it easier when using the data on the phone for plotting points. – nhunston Mar 01 '11 at 00:30
  • 33
    Bad solution. Floats have finite precision; this can truncate significant digits. – mpen Nov 04 '13 at 21:41
  • 5
    I don't think this was a bad solution, I think it's one of the better solutions for this language, if the OP requires precision, then the OP should look at using C, C#, Python etc that do support finite precision. – RobertPitt Feb 26 '14 at 17:52
  • 8
    i guess those wont be useful if the number is "0.0000085" for example, result will be something like "8.5E-5" – trrrrrrm Apr 30 '14 at 07:42
  • 3
    lol, dude, simply add the string to 0 ($a += 0;) ... the way your answer started started I thought you were better than the rest here – Nabeel Khan Apr 17 '16 at 00:12
  • @NabeelKhan I know, right? Somebody did post exactly that solution but it's just not getting the love that this answer is getting for some reason. – Okonomiyaki3000 Jan 06 '17 at 05:40
  • @Okonomiyaki3000 but we know at least :) – Nabeel Khan Jan 17 '17 at 19:38
  • your solution only works if no special locale is set. For instance, a German String would be `$s = "37,45340000000000"`, and then your cast to float will fail. – olidem Jul 10 '18 at 21:13
  • 3
    Bad answer.. it fails if the number has thousand separators – Hike Nalbandyan Sep 12 '18 at 15:00
52

Try with rtrim:

$number = rtrim($number, "0");

If you have a decimal number terminating in 0's (e.g. 123.000), you may also want to remove the decimal separator, which may be different depending on the used locale. To remove it reliably, you may do the following:

$number = rtrim($number, "0");
$locale_info = localeconv();
$number = rtrim($number, $locale_info['decimal_point']);

This of course is not a bullet-proof solution, and may not be the best one. If you have a number like 12300.00, it won't remove the trailing 0's from the integer part, but you can adapt it to your specific need.

jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • 24
    In my case, I did the following: rtrim(rtrim($number, "0"),".") Because I also had to remove the decimal if a whole number was being shown (for example, this will show numbers 2.00, 1.00, 28.50, 16.25 I wanted to show as 2, 1, 28.5, 16.25, rather than 2., 1., 28.5, 16.25) – Warren Sergent Oct 17 '12 at 23:22
  • 3
    I like this solution because you can preserve commas inserted with number_format: rtrim(rtrim(number_format($number, 2), '0'), '.') In my case, I don't need to worry about whole numbers like 100, because I'm pulling a decimal value from the database. – Staysee Dec 14 '15 at 18:08
  • @Staysee isn't it possible that you pull a decimal value from the database that looks like: `"123.0000000"`? Now what do you have? – Okonomiyaki3000 Jan 06 '17 at 05:46
  • Updated the answer to show how to also remove the decimal separator according to the current locale. – jweyrich Jan 06 '17 at 11:58
  • Suppose you got a string like `".000"`. I suppose you'd want your function to return `"0"` instead of `""`. – Okonomiyaki3000 Jun 26 '18 at 00:52
  • rtrim(rtrim($num, '0'), '.'); work fine for me. – Ali Ghasemzadeh May 08 '22 at 07:33
41

You'll run into a lot of trouble if you try trimming or other string manipulations. Try this way.

$string = "37.422005000000000000000000000000";

echo $string + 0;

Outputs:

37.422005
Okonomiyaki3000
  • 3,628
  • 23
  • 23
  • 3
    Excellent solution. Any idea how this works? Coz it does work – Onimusha Jun 15 '15 at 20:06
  • 3
    It's very simple. You start out with a string that has a lot of trailing zeros. PHP cannot add the integer `0` to a string so it first converts the string to a numeric type then adds `0` to it. You end up with a number, not a string. Numeric types have no use for trailing zeroes. You should be careful about automatic type conversion but in a case like this, it's entirely predictable and safe. – Okonomiyaki3000 Jun 17 '15 at 08:39
  • Wow! I think this is the definition of "too good to be true"! Like someone already observed, this could do with a little explanation. – Ifedi Okonkwo Jun 21 '18 at 08:23
  • @IfediOkonkwo Thanks. I already posted an explanation in the comments. – Okonomiyaki3000 Jun 21 '18 at 09:05
  • +1 from me. This is better solution than ```rtrim```. If the number has no any other number behind decimal (ex : **8.00000000**), ```rtrim``` will strangely get result **8.** when printed as String, it has annoying unnecessary dot of course, while this solution gives solid result **8** which is desired by everyone. Seriously, PHP always do something that is Mathematically illegal move. – poring91 Jun 17 '21 at 21:47
  • 1
    @poring91 you can't call the behavior of `rtrim` 'mathematically illegal`. It is not math function and it's not operating on a number. It's a string function operating on a string and it's doing exactly what it's supposed to do. It's just not the appropriate function for this case. – Okonomiyaki3000 Jun 19 '21 at 10:12
  • @Okonomiyaki3000 I understand about that. For clarification, the thing I said about "Mathematically illegal move" is when calculate string data with number data like this solution. The operation PHP do is... convert string that is shaped like number to appropriate number and calculate it in mathematically way. We all know that String is array, and calculate a group of data with single of data because the array is shaped like number is illegal move, by doing so feels like PHP is cheating the logic. Yes, it gives programmer easy access and it helps me. – poring91 Jun 19 '21 at 11:51
  • other language might doing different behavior such as appending string like BASIC or reject it because the operator cannot process array and primitive data (I forget which language it was) – poring91 Jun 19 '21 at 11:59
  • Whilst this works for the OPs question, this solution will error if the number being trimmed is in thousands and uses comma separators. – Alluziion Sep 29 '21 at 09:14
10

In my case, I did the following, extending other answers here:

rtrim((strpos($number,".") !== false ? rtrim($number, "0") : $number),".");

Because I also had to remove the decimal if a whole number was being shown

As an example, this will show the following numbers

2.00, 1.00, 28.50, 16.25 

As

2, 1, 28.5, 16.25

Rather than

2., 1., 28.5, 16.25

Which, to me, is not showing them correctly.

Latest edit also stops numbers such as "100" from being rtrim'ed to 1, by only trimming the rightmost 0's if a decimal is encountered.

Warren Sergent
  • 2,542
  • 4
  • 36
  • 42
  • 2
    Will fail on numbers such as "100" (strips significant 0s). – mpen Nov 04 '13 at 21:39
  • Thanks Mark, solution has been updated (albeit 18 months after your comment!) – Warren Sergent Apr 17 '15 at 22:32
  • 1
    Redacted my downvote. Looks a lot like [my answer](http://stackoverflow.com/a/19777740/65387) now. – mpen Apr 17 '15 at 23:31
  • What will happen if you start with `".000"`? – Okonomiyaki3000 Jun 26 '18 at 01:00
  • Exactly what you would expect to happen. It would return an empty string - because you've stripped out the zeroes AND the decimal place... the issue here is that the original request was asking about STRING manipulation, and not working with actual numbers. IF you needed it to return a numeric value, you could `(float)rtrim((strpos($number,".") !== false ? rtrim($number, "0") : $number),".");` or simply `+0` to the original string. – Warren Sergent Jun 28 '18 at 20:32
9

You can also use floatval(val);.

 <?php
 echo floatval( "37.422005000000000000000000000000" );
 ?>

results in

37.422005

Farray
  • 8,290
  • 3
  • 33
  • 37
  • 2
    I don't think it's the best choice in the first place but, if you're going to convert to a float, don't use `floatval()`. Just cast it as a float with `(float)`. Always avoid calling extra functions if possible. The use case for `floatval()` is when you want to convert a whole array of values to float, then you can call `array_map('floatval', $someArray);` – Okonomiyaki3000 Jan 06 '17 at 05:49
  • 2
    Both `floatval` and `(float)` turn my number into scientific notation `.0E-7` – jaggedsoft Sep 08 '18 at 12:36
7

Most of these solutions will trim significant digits in numbers such as "100" (no trailing decimal). Here's a simple solution that doesn't have this problem:

function TrimTrailingZeroes($nbr) {
    if(strpos($nbr,'.')!==false) $nbr = rtrim($nbr,'0');
    return rtrim($nbr,'.') ?: '0';
}

I think that covers all the different scenarios.

>>> TrimTrailingZeroes('0')
=> "0"
>>> TrimTrailingZeroes('01')
=> "01"
>>> TrimTrailingZeroes('01.0')
=> "01"
>>> TrimTrailingZeroes('01.01')
=> "01.01"
>>> TrimTrailingZeroes('01.010')
=> "01.01"
>>> TrimTrailingZeroes('.0')
=> "0"
>>> TrimTrailingZeroes('.1')
=> ".1"
>>> TrimTrailingZeroes('.10')
=> ".1"
>>> TrimTrailingZeroes('3141592653589793.238462643383279502880000000000000000000000000000')
=> "3141592653589793.23846264338327950288"
mpen
  • 272,448
  • 266
  • 850
  • 1,236
6

If you want to strip the excess zeros away from the end but only to a certain decimal place, this is a useful expression to do just that (for example 0.30000 will show 0.30 and 0.0003000 will show 0.0003).

preg_replace("/(?<=\\.[0-9]{2})[0]+\$/","",$number);

Of course the {2} controls the decimal place limit.

scott klarr
  • 69
  • 1
  • 1
  • 10
    +1 for using the most complex way to solve a simple problem :-) – Gerben Jun 22 '12 at 20:06
  • `"0.0003000"` will **not** convert to `"0.0003"`. You've only allowed for up to 2 non-zero digits after the decimal. This regex won't even match. You're better off using `number_format($x,2,'.','')` if this is the result you want. – mpen Oct 06 '15 at 15:53
  • Do not use regular expressions for something like this. Especially don't use such a overly complex regular expression. – Okonomiyaki3000 Jan 06 '17 at 05:52
  • simple yet beautiful solution! – Kidd Tang May 31 '22 at 07:00
3

Trims trailing zeroes, but only after the decimal place -- we wouldn't want to convert 100 -> 1, for example. It will also strip the period if only zeros follow it.

function trim_zeros($str) {
    if(!is_string($str)) return $str;
    return preg_replace(array('`\.0+$`','`(\.\d+?)0+$`'),array('','$1'),$str);
}
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • At least you've considered a case that almost everyone else has ignored. Still, no. – Okonomiyaki3000 Jan 06 '17 at 05:53
  • @Okonomiyaki3000 What's your beef with this solution? Yours doesn't allow arbitrarily large numbers/high precision. – mpen Jan 06 '17 at 17:51
  • Maybe it's just me but I try to avoid preg functions unless they're absolutely necessary. Still, if you need precision of over 14 decimal places or so, this might be the best solution. – Okonomiyaki3000 Jan 10 '17 at 00:53
  • 1
    @Okonomiyaki3000 Regexes aren't really slow unless you're running thousands of them. Still, I did come up with another solution that doesn't require them: http://stackoverflow.com/a/19777740/65387 – mpen Jan 10 '17 at 02:09
3

You should use the round function which is more able to manipulate numbers than a replace.

round('37.422005000000000000000000000000', 32); 
//float(37.422005)

round('-122.84095000000000000000000000000', 32); 
//float(-122.84095)

The resulting rounded number will be based upon your precision (default 14) setting.

Will B.
  • 17,883
  • 4
  • 67
  • 69
William Durand
  • 5,439
  • 1
  • 26
  • 37
  • Oddly this is actually a [viable solution](https://3v4l.org/R3CN9), by specifying a high precision like `32`, it prevents the supplied number from being rounded. `round('-122.84095000000000000000000000000', 32) = -122.84095` However since it converts the value to a real number, it still suffers from the floating point issue that casting the string value does when working with high `ini_set('precision', 32)`. – Will B. May 02 '19 at 17:45
  • Good solution, but it works just for 4 decimal places in my case. for 5, ... it shows `e` – Arash Younesi Jun 04 '21 at 11:14
3

If you want a solution that accepts a minimum and maximum amount of decimal places, this should work:

/**
 * Displays up to 4 decimal places, with a minimum of 2 decimal places, trimming unnecessary zeroes
 *
 * @param mixed $number
 * @param int $minimumDecimals
 * @param int $maximumDecimals
 * @return string
 */
function rate_format($number, int $minimumDecimals = 2, int $maximumDecimals = 4): string
{
    $formatted = number_format($number, $maximumDecimals, '.', ',');
    $minimumLength = strpos($formatted, '.') + $minimumDecimals + 1;
    $extra = rtrim(substr($formatted, $minimumLength), "0");
    return substr($formatted, 0, $minimumLength) . $extra;
}


// rate_format("1.2500") returns "1.25"
// rate_format("1.2525") returns "1.2525"
// rate_format("1.25256") returns "1.2526"
// rate_format("1") returns "1.00"

This is hard coded to use the US locale, but should be easily adjusted for other locales.

Devon Bessemer
  • 34,461
  • 9
  • 69
  • 95
3

Remove Trailing zeros + Thousand Separator

function specialFormat($number,  $decimals = 8)
{
    return rtrim(rtrim(number_format($number, $decimals), '0'), '.');
}

input: 0.00000008 => output: 0.00000008
input: 1560.1854500 => output: 1,560.18545
input: 1560.00 => output: 1,560
Arash Younesi
  • 1,671
  • 1
  • 14
  • 23
1

For me, I need a further solution to convert exponential values and simple numbers like 10000 to the last non-zero significant digit

/* Convert any value to the least significant value */
function toDecimal($val) {

  // Convert any exponential sign to proper decimals
  $val = sprintf("%lf", $val);

  if (strpos($val, '.') !== false) {
      $val = rtrim(rtrim($val, '0'), '.');
  }

  return $val;
}

// Test cases
echo toDecimal(1000.000) . "\n";
echo toDecimal(1E-5) . "\n";
echo toDecimal(1E+5) . "\n";
echo toDecimal(1234.56) . "\n";
echo toDecimal(1234.5700) . "\n";
echo toDecimal(1234000) . "\n";
echo toDecimal(-1e10) . "\n";

// Results
1000
0.00001
100000
1234.56
1234.57
1234000
-10000000000
Joe Kuan
  • 119
  • 1
  • 3
  • No. With the exception of `1E-5` (which has nothing to do with this question), all of these 'tests' would turn out exactly the same without running them through your function. – Okonomiyaki3000 Jan 06 '17 at 06:02
0

hmm, interesting. I have used this:

// remove leading zeros
$output = ltrim ($output, "0");

// remove trailing 0s.
$temp=explode(".",$output);
$temp[1]=rtrim($temp[1],"0");
$output = $temp[0];
if (!empty($temp[1])) $output.='.'.$temp[1];

return $output;

This removes trailing 0s from the number AFTER the first decimal point. Otherwise a number like 100 becomes 1.

Since I was doing a comparison, using the float technique caused problems. Hope this helps?

Dan
  • 9
  • 1
0

You can use rtrim() ( http://www.php.net/manual/en/function.rtrim.php ):

rtrim( "37.422005000000000000000000000000" , "0" )

Just make sure that there will be a decimal point.

linepogl
  • 9,147
  • 4
  • 34
  • 45
-3

preg_replace will do the trick:

$lat=preg_replace('/0+$/','',$lat);
Shad
  • 15,134
  • 2
  • 22
  • 34
  • -1 because although this works, this is not a good use-case for regex. – UnkwnTech Mar 01 '11 at 00:38
  • @Unkwntech too processor intensive for the simplicity of the task? – Shad Mar 01 '11 at 00:45
  • 2
    @Shad, just overkill. Regular Expressions are usually not the answer, if one can use type (string/int/float) manipulations it is likely to be faster, and less prone to problems in the future. For example compare your solution to RobertPitt's solution, in yours what happens if $lat is `10`, and what happens in RobertPitt's? Those reasons aside, also consider what happens when a developer who doesn't know regular expressions comes across your solution while trying to fix a bug. – UnkwnTech Mar 01 '11 at 00:56
  • One more reason not to do this, consider the string: `"123.0000000"` – Okonomiyaki3000 Jan 06 '17 at 05:43