Nice PHP algorithm to convert 120000000 into '120 mil'? - php

I've been struggling to find a nice algorithm to change a number (could be a float or integer) into a nicely formated human readable number showing the units as a string. For example:
100500000 -> '100.5 Mil'
200400 -> '200.4 K'
143000000 -> '143 Mil'
52000000000 -> '52 Bil'
etc, you get the idea.
Any pointers?

I'd adapt the code below (which i found on the net):
Code credit goes to this link i found: http://www.phpfront.com/php/human-readable-byte-format/
function humanReadableOctets($octets)
{
$units = array('B', 'kB', 'MB', 'GB', 'TB'); // ...etc
for ($i = 0, $size =$octets; $size>1024; $size=$size/1024)
$i++;
return number_format($size, 2) . ' ' . $units[min($i, count($units) -1 )];
}
Don't forget to change 1024 to 1000 though ...

<?php
function prettyNumber($number) // $number is int / float
{
$orders = Array("", " K", " Mil", " Bil");
$order=0;
while (($number/1000.0) >= 1.5) { // while the next step up would generate a number greater than 1.5
$order++;
$number/=1000.0;
}
if ($order)
return preg_replace("/\.?0+$/", "",
substr(number_format($number, 2),0,5)).$orders[$order];
return $number;
}
$tests = array(100500000,200400,143000000,52000000000);
foreach ($tests as $test)
{
echo $test." -> '".prettyNumber($test)."'\n";
}

Here is a log() version if you are still interested:
function wordify($val, $decimalPlaces = 1) {
if ($val < 1000 && $val > -1000)
return $val;
$a = array( 0 => "", 1 => "K", 2 => "Mil", 3 => "Bil", 4 => "Tril", 5 => "Quad" );
$log1000 = log(abs($val), 1000);
$suffix = $a[$log1000];
return number_format($val / pow(1000, floor($log1000)), $decimalPlaces, '.', '') . " $suffix";
}
$tests = array(-1001, -970, 0, 1, 929, 1637, 17000, 123456, 1000000, 1000000000, 1234567890123);
foreach ($tests as $num) {
echo wordify($num)."<br>";
}

found this
this one might be better for you
might be a good start

there is similar code here:
http://aidanlister.com/2004/04/human-readable-file-sizes/

Related

PHP Remove Unnecessary Zero In Decimals Works, But Not With This Number [duplicate]

I'm trying to find a fast way to remove zero decimals from number values like this:
echo cleanNumber('125.00');
// 125
echo cleanNumber('966.70');
// 966.7
echo cleanNumber(844.011);
// 844.011
Does exists some optimized way to do that?
$num + 0 does the trick.
echo 125.00 + 0; // 125
echo '125.00' + 0; // 125
echo 966.70 + 0; // 966.7
Internally, this is equivalent to casting to float with (float)$num or floatval($num) but I find it simpler.
you could just use the floatval function
echo floatval('125.00');
// 125
echo floatval('966.70');
// 966.7
echo floatval('844.011');
// 844.011
This is what I use:
function TrimTrailingZeroes($nbr) {
return strpos($nbr,'.')!==false ? rtrim(rtrim($nbr,'0'),'.') : $nbr;
}
N.B. This assumes . is the decimal separator. It has the advantage that it will work on arbitrarily large (or small) numbers since there is no float cast. It also won't turn numbers into scientific notation (e.g. 1.0E-17).
If you want to remove the zero digits just before to display on the page or template.
You can use the sprintf() function
sprintf('%g','125.00');
// 125
‌‌sprintf('%g','966.70');
// 966.7
‌‌‌‌sprintf('%g',844.011);
// 844.011
Simply adding + to your string variable will cause typecast to (float) and removes zeros:
var_dump(+'125.00'); // double(125)
var_dump(+'966.70'); // double(966.7)
var_dump(+'844.011'); // double(844.011)
var_dump(+'844.011asdf');// double(844.011)
For everyone coming to this site having the same problem with commata instead, change:
$num = number_format($value, 1, ',', '');
to:
$num = str_replace(',0', '', number_format($value, 1, ',', '')); // e.g. 100,0 becomes 100
If there are two zeros to be removed, then change to:
$num = str_replace(',00', '', number_format($value, 2, ',', '')); // e.g. 100,00 becomes 100
More here: PHP number: decimal point visible only if needed
You should cast your numbers as floats, which will do this for you.
$string = "42.422005000000000000000000000000";
echo (float)$string;
Output of this will be what you are looking for.
42.422005
$x = '100.10';
$x = preg_replace("/\.?0*$/",'',$x);
echo $x;
There is nothing that can't be fixed with a simple regex ;)
http://xkcd.com/208/
Typecast to a float.
$int = 4.324000;
$int = (float) $int;
Be careful with adding +0.
echo number_format(1500.00, 2,".",",")+0;
//1
Result of this is 1.
echo floatval('1,000.00');
// 1
echo floatval('1000.00');
//1000
Sometimes, especially in case of monetary amounts, you want to remove the zeros only if they are 2, you don't want to print € 2.1 instead of € 2.10.
An implementation could be:
function formatAmount(string|float|int $value, int $decimals = 2): string
{
if (floatval(intval($value)) === floatval($value)) {
// The number is an integer. Remove all the decimals
return (string)intval($value);
}
return number_format($value, $decimals);
}
Examples of expected outputs:
0.1000 => 0.10
20.000 => 20
1.25 => 1.25
Example 1
$value =81,500.00;
{{rtrim(rtrim(number_format($value,2),0),'.')}}
output
81,500
Example 2
$value=110,763.14;
{{rtrim(rtrim(number_format($value,2),0),'.')}}
output
110,763.14
Due to this question is old. First, I'm sorry about this.
The question is about number xxx.xx but in case that it is x,xxx.xxxxx or difference decimal separator such as xxxx,xxxx this can be harder to find and remove zero digits from decimal value.
/**
* Remove zero digits (include zero trails - 123.450, 123.000) from decimal value.
*
* #param string|int|float $number The number can be any format, any where use in the world such as 123, 1,234.56, 1234.56789, 12.345,67, -98,765.43
* #param string The decimal separator. You have to set this parameter to exactly what it is. For example: in Europe it is mostly use "," instead of ".".
* #return string Return removed zero digits from decimal value. Only return as string!
*/
function removeZeroDigitsFromDecimal($number, $decimal_sep = '.')
{
$explode_num = explode($decimal_sep, $number);
if (is_countable($explode_num) && count($explode_num) > 1) {
// if exploded number is more than 1 (Example: explode with . for nnnn.nnn is 2)
// replace `is_countable()` with `is_array()` if you are using PHP older than 7.3.
$explode_num[count($explode_num)-1] = preg_replace('/(0+)$/', '', $explode_num[count($explode_num)-1]);
if ($explode_num[count($explode_num)-1] === '') {
// if the decimal value is now empty.
// unset it to prevent nnn. without any number.
unset($explode_num[count($explode_num)-1]);
}
$number = implode($decimal_sep, $explode_num);
}
unset($explode_num);
return (string) $number;
}
And here is the code for test.
$tests = [
1234 => 1234,
-1234 => -1234,
'12,345.67890' => '12,345.6789',
'-12,345,678.901234' => '-12,345,678.901234',
'12345.000000' => '12345',
'-12345.000000' => '-12345',
'12,345.000000' => '12,345',
'-12,345.000000000' => '-12,345',
];
foreach ($tests as $number => $assert) {
$result = removeZeroDigitsFromDecimal($number);
assert($result === (string) $assert, new \Exception($result . ' (' . gettype($result) . ') is not matched ' . $assert . ' (' . gettype($assert) . ')'));
echo $number . ' => ' . (string) $assert . '<br>';
}
echo '<hr>' . PHP_EOL;
$tests = [
1234 => 1234,
-1234 => -1234,
'12.345,67890' => '12.345,6789',
'-12.345.678,901234' => '-12.345.678,901234',
'12345,000000' => '12345',
'-12345,000000' => '-12345',
'-12.345,000000000' => '-12.345',
'-12.345,000000,000' => '-12.345,000000',// this is correct assertion. Weird ,000000,000 but only last 000 will be removed.
];
foreach ($tests as $number => $assert) {
$result = removeZeroDigitsFromDecimal($number, ',');
assert($result === (string) $assert, new \Exception($result . ' (' . gettype($result) . ') is not matched ' . $assert . ' (' . gettype($assert) . ')'));
echo $number . ' => ' . (string) $assert . '<br>';
}
All tests should be pass and no errors.
Why '-12.345,000000,000' will be '-12.345,000000' not '-12.345'?
Because this function is for remove zero digits (include zero trails) from decimal value. It is not validation for the correct number format. That should be another function.
Why always return as string?
Because it is better to use in calculation with bcxxx functions, or use with big number.
$str = 15.00;
$str2 = 14.70;
echo rtrim(rtrim(strval($str), "0"), "."); //15
echo rtrim(rtrim(strval($str2), "0"), "."); //14.7
I found this solution is the best:
public function priceFormat(float $price): string
{
//https://stackoverflow.com/a/14531760/5884988
$price = $price + 0;
$split = explode('.', $price);
return number_format($price, isset($split[1]) ? strlen($split[1]) : 2, ',', '.');
}
The following is much simpler
if(floor($num) == $num) {
echo number_format($num);
} else {
echo $num;
}
You can try the following:
rtrim(number_format($coin->current_price,6),'0.')
Complicated way but works:
$num = '125.0100';
$index = $num[strlen($num)-1];
$i = strlen($num)-1;
while($index == '0') {
if ($num[$i] == '0') {
$num[$i] = '';
$i--;
}
$index = $num[$i];
}
//remove dot if no numbers exist after dot
$explode = explode('.', $num);
if (isset($explode[1]) && intval($explode[1]) <= 0) {
$num = intval($explode[0]);
}
echo $num; //125.01
the solutions above are the optimal way but in case you want to have your own you could use this. What this algorithm does it starts at the end of string and checks if its 0, if it is it sets to empty string and then goes to the next character from back untill the last character is > 0
$value = preg_replace('~\.0+$~','',$value);
You can use:
print (floatval)(number_format( $Value), 2 ) );
Thats my small solution...
Can included to a class and set vars
private $dsepparator = '.'; // decimals
private $tsepparator= ','; // thousand
That can be set by constructor and change to users lang.
class foo
{
private $dsepparator;
private $tsepparator;
function __construct(){
$langDatas = ['en' => ['dsepparator' => '.', 'tsepparator' => ','], 'de' => ['dsepparator' => ',', 'tsepparator' => '.']];
$usersLang = 'de'; // set iso code of lang from user
$this->dsepparator = $langDatas[$usersLang]['dsepparator'];
$this->tsepparator = $langDatas[$usersLang]['tsepparator'];
}
public function numberOmat($amount, $decimals = 2, $hideByZero = false)
{
return ( $hideByZero === true AND ($amount-floor($amount)) <= 0 ) ? number_format($amount, 0, $this->dsepparator, $this->tsepparator) : number_format($amount, $decimals, $this->dsepparator, $this->tsepparator);
}
/*
* $bar = new foo();
* $bar->numberOmat('5.1234', 2, true); // returns: 5,12
* $bar->numberOmat('5', 2); // returns: 5,00
* $bar->numberOmat('5.00', 2, true); // returns: 5
*/
}
This is my solution.
I want to keep ability to add thousands separator
$precision = 5;
$number = round($number, $precision);
$decimals = strlen(substr(strrchr($number, '.'), 1));
return number_format($number, $precision, '.', ',');
This is a simple one line function using rtrim, save separator and decimal point :
function myFormat($num,$dec)
{
return rtrim(rtrim(number_format($num,$dec),'0'),'.');
}
Simple and accurate!
function cleanNumber($num){
$explode = explode('.', $num);
$count = strlen(rtrim($explode[1],'0'));
return bcmul("$num",'1', $count);
}
I use this simple code:
define('DECIMAL_SEPARATOR', ','); //To prove that it works with different separators than "."
$input = "50,00";
$number = rtrim($input, '0'); // 50,00 --> 50,
$number = rtrim($number, DECIMAL_SEPARATOR); // 50, --> 50
echo $number;
Seems a bit too easy to be the really correct solution, but it works just fine for me. You should do some tests with the inputs you'll be getting before using this.
Assuming the amount is a string with 2 decimal places, then you can use:
protected function removeZerosDecimals(string $money): string
{
$formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$uselessDecimals = sprintf(
'%s00',
$formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL)
);
if (!str_ends_with($money, $uselessDecimals)) {
return $money;
}
$len = mb_strlen($money);
return mb_substr($money, 0, $len - mb_strlen($uselessDecimals));
}
That will work as expected for ?any? currency, like $500.00 and R$ 500,00.
function removeZerosAfterDecimals($number) {
$number = trim($number);
if($number <= 0 || empty($number)) {
return $number;
}
$ary = explode('.', $number);
if(count($ary) <= 1) {
return $number;
}
$reverseAry = array_reverse($ary);
$endSearch = false;
$newNumber = [];
for($i=0; $i<count($reverseAry); $i++) {
if($reverseAry[$i] != 0 && $endSearch === false) {
$newNumber[] = $reverseAry[$i];
$endSearch = true;
} else if ($endSearch === true) {
$newNumber[] = $reverseAry[$i];
}
}
return implode('.',array_reverse($newNumber));
}
//output: 10.0.1.0 => 10.0.1
//output: 10.0.1 => 10.0.1
//output: 10.1.2 => 10.1.2
//output: 10.0.0 => 10
This function will only remove the trailing zero decimals
This Code will remove zero after point and will return only two decimal digits.
$number=1200.0000;
str_replace('.00', '',number_format($number, 2, '.', ''));
Output will be: 1200
Ultimate Solution: The only safe way is to use regex:
echo preg_replace("/\.?0+$/", "", 3.0); // 3
echo preg_replace("/\d+\.?\d*(\.?0+)/", "", 3.0); // 3
it will work for any case

Round number up to closest value in array

I've created an array with 'maximum' values in.
$management = array(
'100' => '1',
'500' => '2',
'1000' => '3',
);
And created a loop to find the closest value, rounding it up.
$speed = 10;
$r= '';
sort($management);
foreach($management as $mgmt => $name) {
if($mgmt >= $speed) {
$r= $name;
}
}
$r= end($management);
So, where the $speed is 10, it should pick up the array key 100 and if it was 100 it should still pickup 100 but if the speed was 200, it would pickup 500
The above is picking up 500 when the $speed is 10 though.
Can anyone help please?
You have a couple of problems with your code. Firstly, the call to sort rewrites all the keys of the $management array which you are using for the comparison; you need to use ksort instead to sort by the keys instead of the values. Secondly, since the keys are in ascending order, once one is greater than the $speed value, they all will be, so you need to break from the loop once you find a higher value. Try this instead:
$r= '';
ksort($management);
foreach($management as $mgmt => $name) {
if($mgmt >= $speed) {
$r= $name;
break;
}
}
echo $r;
Demo on 3v4l.org
this is an example on how you can do it :
$array = array(1, 10, 100, 200, 400, 500, 1000);
public function getArrayRoundUp($array, $number) {
sort($array);
foreach ($array as $a) {
if ($a >= $number) return $a;
}
return end($array);
}
$value = 950;
$nearest = getArrayRoundUp($array, $value);
//the expect result will be 1000
echo $nearest;
Use the following function
function find(array $array, $search)
{
$last = null; // return value if $array array is empty
foreach ($array as $key => $value) {
if ($key >= $search) {
return $key; // found it, return quickly
}
$last = $key; // keep the last key thus far
}
return $last;
}
Tested and Working:-
echo find($management, 100); // Will result 100
echo find($management, 200); //Will result 500

PHP Compare integers

I have the following integers
7
77
0
20
in an array. I use them to check from where a call originated.
Numbers like 730010123, 772930013, 20391938.
What I need to do is I need a way to check if the number starts with 7 or 77 for an example.
Is there any way to do this in PHP and avoid a thousand if statements?
One issue I am having is that if I check if the number starts with 7 the numbers that start with 77 are being called as well. Note that 7 numbers are mobile and 77 are shared cost numbers and not equal in any way so I need to separate them.
if (substr($str, 0, 1) == '7') ||{
if (substr($str, 0, 2) == '77'){
//starts with '77'
} else {
//starts with '7'
}
}
I made a little example with a demo array, I hope you can use it:
$array = array(
7 => 'Other',
70 => 'Fryslan!',
20 => 'New York',
21 => 'Dublin',
23 => 'Amsterdam',
);
$number = 70010123;
$place = null;
foreach($array as $possibleMatch => $value) {
if (preg_match('/^' . (string)$possibleMatch . '/', (string)$number))
$place = $value;
}
echo $place;
The answer in this case is "Fryslan". You have to remember that 7 also matches in this case? So you may want to add some metric system in case of two matches.
Is this you want?
<?php
$myarray = array(730010123, 772930013, 20391938);
foreach($myarray as $value){
if(substr($value, 0, 2) == "77"){
echo "Starting With 77: <br/>";
echo $value;
echo "<br>";
}
if((substr($value, 0, 1) == "7")&&(substr($value, 0, 2) != "77")){
echo "Starting With 7: <br/>";
echo $value;
echo "<br>";
}
}
?>
You could use preg_match and array_filter for that
function check_digit($var) {
return preg_match("/^(7|77|0)\d+$/");
}
$array_to_be_check = array("730010123" , "772930013", "20391938");
print_r(array_filter($array_to_be_check, "check_digit"));
A way to do this is to handle the "integer" you received as a number as being a string.
Doing so by something like this:
$number = 772939913;
$filter = array (
'77' => 'type1',
'20' => 'type2',
'7' => 'type3',
'0' => 'type4');
$match = null;
foreach ($filter as $key => $val){
$comp = substr($number, 0, strlen($key));
if ($comp == $key){
$match = $key;
break;
}
}
if ($match !== null){
echo 'the type is: ' . $filter[$match];
//you can proceed with your task
}

Remove useless zero digits from decimals in PHP

I'm trying to find a fast way to remove zero decimals from number values like this:
echo cleanNumber('125.00');
// 125
echo cleanNumber('966.70');
// 966.7
echo cleanNumber(844.011);
// 844.011
Does exists some optimized way to do that?
$num + 0 does the trick.
echo 125.00 + 0; // 125
echo '125.00' + 0; // 125
echo 966.70 + 0; // 966.7
Internally, this is equivalent to casting to float with (float)$num or floatval($num) but I find it simpler.
you could just use the floatval function
echo floatval('125.00');
// 125
echo floatval('966.70');
// 966.7
echo floatval('844.011');
// 844.011
This is what I use:
function TrimTrailingZeroes($nbr) {
return strpos($nbr,'.')!==false ? rtrim(rtrim($nbr,'0'),'.') : $nbr;
}
N.B. This assumes . is the decimal separator. It has the advantage that it will work on arbitrarily large (or small) numbers since there is no float cast. It also won't turn numbers into scientific notation (e.g. 1.0E-17).
If you want to remove the zero digits just before to display on the page or template.
You can use the sprintf() function
sprintf('%g','125.00');
// 125
‌‌sprintf('%g','966.70');
// 966.7
‌‌‌‌sprintf('%g',844.011);
// 844.011
Simply adding + to your string variable will cause typecast to (float) and removes zeros:
var_dump(+'125.00'); // double(125)
var_dump(+'966.70'); // double(966.7)
var_dump(+'844.011'); // double(844.011)
var_dump(+'844.011asdf');// double(844.011)
For everyone coming to this site having the same problem with commata instead, change:
$num = number_format($value, 1, ',', '');
to:
$num = str_replace(',0', '', number_format($value, 1, ',', '')); // e.g. 100,0 becomes 100
If there are two zeros to be removed, then change to:
$num = str_replace(',00', '', number_format($value, 2, ',', '')); // e.g. 100,00 becomes 100
More here: PHP number: decimal point visible only if needed
You should cast your numbers as floats, which will do this for you.
$string = "42.422005000000000000000000000000";
echo (float)$string;
Output of this will be what you are looking for.
42.422005
$x = '100.10';
$x = preg_replace("/\.?0*$/",'',$x);
echo $x;
There is nothing that can't be fixed with a simple regex ;)
http://xkcd.com/208/
Typecast to a float.
$int = 4.324000;
$int = (float) $int;
Be careful with adding +0.
echo number_format(1500.00, 2,".",",")+0;
//1
Result of this is 1.
echo floatval('1,000.00');
// 1
echo floatval('1000.00');
//1000
Sometimes, especially in case of monetary amounts, you want to remove the zeros only if they are 2, you don't want to print € 2.1 instead of € 2.10.
An implementation could be:
function formatAmount(string|float|int $value, int $decimals = 2): string
{
if (floatval(intval($value)) === floatval($value)) {
// The number is an integer. Remove all the decimals
return (string)intval($value);
}
return number_format($value, $decimals);
}
Examples of expected outputs:
0.1000 => 0.10
20.000 => 20
1.25 => 1.25
Example 1
$value =81,500.00;
{{rtrim(rtrim(number_format($value,2),0),'.')}}
output
81,500
Example 2
$value=110,763.14;
{{rtrim(rtrim(number_format($value,2),0),'.')}}
output
110,763.14
Due to this question is old. First, I'm sorry about this.
The question is about number xxx.xx but in case that it is x,xxx.xxxxx or difference decimal separator such as xxxx,xxxx this can be harder to find and remove zero digits from decimal value.
/**
* Remove zero digits (include zero trails - 123.450, 123.000) from decimal value.
*
* #param string|int|float $number The number can be any format, any where use in the world such as 123, 1,234.56, 1234.56789, 12.345,67, -98,765.43
* #param string The decimal separator. You have to set this parameter to exactly what it is. For example: in Europe it is mostly use "," instead of ".".
* #return string Return removed zero digits from decimal value. Only return as string!
*/
function removeZeroDigitsFromDecimal($number, $decimal_sep = '.')
{
$explode_num = explode($decimal_sep, $number);
if (is_countable($explode_num) && count($explode_num) > 1) {
// if exploded number is more than 1 (Example: explode with . for nnnn.nnn is 2)
// replace `is_countable()` with `is_array()` if you are using PHP older than 7.3.
$explode_num[count($explode_num)-1] = preg_replace('/(0+)$/', '', $explode_num[count($explode_num)-1]);
if ($explode_num[count($explode_num)-1] === '') {
// if the decimal value is now empty.
// unset it to prevent nnn. without any number.
unset($explode_num[count($explode_num)-1]);
}
$number = implode($decimal_sep, $explode_num);
}
unset($explode_num);
return (string) $number;
}
And here is the code for test.
$tests = [
1234 => 1234,
-1234 => -1234,
'12,345.67890' => '12,345.6789',
'-12,345,678.901234' => '-12,345,678.901234',
'12345.000000' => '12345',
'-12345.000000' => '-12345',
'12,345.000000' => '12,345',
'-12,345.000000000' => '-12,345',
];
foreach ($tests as $number => $assert) {
$result = removeZeroDigitsFromDecimal($number);
assert($result === (string) $assert, new \Exception($result . ' (' . gettype($result) . ') is not matched ' . $assert . ' (' . gettype($assert) . ')'));
echo $number . ' => ' . (string) $assert . '<br>';
}
echo '<hr>' . PHP_EOL;
$tests = [
1234 => 1234,
-1234 => -1234,
'12.345,67890' => '12.345,6789',
'-12.345.678,901234' => '-12.345.678,901234',
'12345,000000' => '12345',
'-12345,000000' => '-12345',
'-12.345,000000000' => '-12.345',
'-12.345,000000,000' => '-12.345,000000',// this is correct assertion. Weird ,000000,000 but only last 000 will be removed.
];
foreach ($tests as $number => $assert) {
$result = removeZeroDigitsFromDecimal($number, ',');
assert($result === (string) $assert, new \Exception($result . ' (' . gettype($result) . ') is not matched ' . $assert . ' (' . gettype($assert) . ')'));
echo $number . ' => ' . (string) $assert . '<br>';
}
All tests should be pass and no errors.
Why '-12.345,000000,000' will be '-12.345,000000' not '-12.345'?
Because this function is for remove zero digits (include zero trails) from decimal value. It is not validation for the correct number format. That should be another function.
Why always return as string?
Because it is better to use in calculation with bcxxx functions, or use with big number.
$str = 15.00;
$str2 = 14.70;
echo rtrim(rtrim(strval($str), "0"), "."); //15
echo rtrim(rtrim(strval($str2), "0"), "."); //14.7
I found this solution is the best:
public function priceFormat(float $price): string
{
//https://stackoverflow.com/a/14531760/5884988
$price = $price + 0;
$split = explode('.', $price);
return number_format($price, isset($split[1]) ? strlen($split[1]) : 2, ',', '.');
}
The following is much simpler
if(floor($num) == $num) {
echo number_format($num);
} else {
echo $num;
}
You can try the following:
rtrim(number_format($coin->current_price,6),'0.')
Complicated way but works:
$num = '125.0100';
$index = $num[strlen($num)-1];
$i = strlen($num)-1;
while($index == '0') {
if ($num[$i] == '0') {
$num[$i] = '';
$i--;
}
$index = $num[$i];
}
//remove dot if no numbers exist after dot
$explode = explode('.', $num);
if (isset($explode[1]) && intval($explode[1]) <= 0) {
$num = intval($explode[0]);
}
echo $num; //125.01
the solutions above are the optimal way but in case you want to have your own you could use this. What this algorithm does it starts at the end of string and checks if its 0, if it is it sets to empty string and then goes to the next character from back untill the last character is > 0
$value = preg_replace('~\.0+$~','',$value);
You can use:
print (floatval)(number_format( $Value), 2 ) );
Thats my small solution...
Can included to a class and set vars
private $dsepparator = '.'; // decimals
private $tsepparator= ','; // thousand
That can be set by constructor and change to users lang.
class foo
{
private $dsepparator;
private $tsepparator;
function __construct(){
$langDatas = ['en' => ['dsepparator' => '.', 'tsepparator' => ','], 'de' => ['dsepparator' => ',', 'tsepparator' => '.']];
$usersLang = 'de'; // set iso code of lang from user
$this->dsepparator = $langDatas[$usersLang]['dsepparator'];
$this->tsepparator = $langDatas[$usersLang]['tsepparator'];
}
public function numberOmat($amount, $decimals = 2, $hideByZero = false)
{
return ( $hideByZero === true AND ($amount-floor($amount)) <= 0 ) ? number_format($amount, 0, $this->dsepparator, $this->tsepparator) : number_format($amount, $decimals, $this->dsepparator, $this->tsepparator);
}
/*
* $bar = new foo();
* $bar->numberOmat('5.1234', 2, true); // returns: 5,12
* $bar->numberOmat('5', 2); // returns: 5,00
* $bar->numberOmat('5.00', 2, true); // returns: 5
*/
}
This is my solution.
I want to keep ability to add thousands separator
$precision = 5;
$number = round($number, $precision);
$decimals = strlen(substr(strrchr($number, '.'), 1));
return number_format($number, $precision, '.', ',');
This is a simple one line function using rtrim, save separator and decimal point :
function myFormat($num,$dec)
{
return rtrim(rtrim(number_format($num,$dec),'0'),'.');
}
Simple and accurate!
function cleanNumber($num){
$explode = explode('.', $num);
$count = strlen(rtrim($explode[1],'0'));
return bcmul("$num",'1', $count);
}
I use this simple code:
define('DECIMAL_SEPARATOR', ','); //To prove that it works with different separators than "."
$input = "50,00";
$number = rtrim($input, '0'); // 50,00 --> 50,
$number = rtrim($number, DECIMAL_SEPARATOR); // 50, --> 50
echo $number;
Seems a bit too easy to be the really correct solution, but it works just fine for me. You should do some tests with the inputs you'll be getting before using this.
Assuming the amount is a string with 2 decimal places, then you can use:
protected function removeZerosDecimals(string $money): string
{
$formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$uselessDecimals = sprintf(
'%s00',
$formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL)
);
if (!str_ends_with($money, $uselessDecimals)) {
return $money;
}
$len = mb_strlen($money);
return mb_substr($money, 0, $len - mb_strlen($uselessDecimals));
}
That will work as expected for ?any? currency, like $500.00 and R$ 500,00.
function removeZerosAfterDecimals($number) {
$number = trim($number);
if($number <= 0 || empty($number)) {
return $number;
}
$ary = explode('.', $number);
if(count($ary) <= 1) {
return $number;
}
$reverseAry = array_reverse($ary);
$endSearch = false;
$newNumber = [];
for($i=0; $i<count($reverseAry); $i++) {
if($reverseAry[$i] != 0 && $endSearch === false) {
$newNumber[] = $reverseAry[$i];
$endSearch = true;
} else if ($endSearch === true) {
$newNumber[] = $reverseAry[$i];
}
}
return implode('.',array_reverse($newNumber));
}
//output: 10.0.1.0 => 10.0.1
//output: 10.0.1 => 10.0.1
//output: 10.1.2 => 10.1.2
//output: 10.0.0 => 10
This function will only remove the trailing zero decimals
This Code will remove zero after point and will return only two decimal digits.
$number=1200.0000;
str_replace('.00', '',number_format($number, 2, '.', ''));
Output will be: 1200
Ultimate Solution: The only safe way is to use regex:
echo preg_replace("/\.?0+$/", "", 3.0); // 3
echo preg_replace("/\d+\.?\d*(\.?0+)/", "", 3.0); // 3
it will work for any case

Price string to float

I like to convert string with a price to a float value. The price comes from different languages and countries and can look like this:
1,00 €
€ 1.00
1'000,00 EUR
1 000.00$
1,000.00$
1.000,00 EURO
or whatever you can think of...
Not sure I got the full range of possibilities with my examples. I am also not sure if it is possible to make in international convert blindly, maybe I have to use a language code? So for the start Euro and Dollar would be enough.
floatval() is kind of stupid so I need something more here. I think I should first remove all chars beside numbers, , and .. Then fix the , / . and use floatval finally.
Has someone done this before and can help me a little?
I would prefer a solution without regexp ;)
Ok, I tried it myself. What do you think of this?
function priceToFloat($s){
// is negative number
$neg = strpos((string)$s, '-') !== false;
// convert "," to "."
$s = str_replace(',', '.', $s);
// remove everything except numbers and dot "."
$s = preg_replace("/[^0-9\.]/", "", $s);
// remove all seperators from first part and keep the end
$s = str_replace('.', '',substr($s, 0, -3)) . substr($s, -3);
// Set negative number
if( $neg ) {
$s = '-' . $s;
}
// return float
return (float) $s;
}
Here some tests: http://codepad.org/YtiHqsgz
Sorry. I couldn't include the other functions because codepad did not like them. But I compared them and there was trouble with strings like "22 000,76" or "22.000"
Update: As Limitless isa pointed out you might have a look at the build in function money-format.
Removing all the non-numeric characters should give you the price in cents. You can then divide that by 100 to get the 'human readable' price. You could do this with something like the filter_var FILTER_SANITIZE_NUMBER_INT. For example:
$cents = filter_var($input, FILTER_SANITIZE_NUMBER_INT);
$price = floatval($cents / 100);
Above is untested, but something like that is probably what you're looking for.
This function will fix your problem:
function priceToSQL($price)
{
$price = preg_replace('/[^0-9\.,]*/i', '', $price);
$price = str_replace(',', '.', $price);
if(substr($price, -3, 1) == '.')
{
$price = explode('.', $price);
$last = array_pop($price);
$price = join($price, '').'.'.$last;
}
else
{
$price = str_replace('.', '', $price);
}
return $price;
}
price to number
number to price examples
<?php
$number="1.050,50";
$result=str_replace(',','.',str_replace('.','',$number));
echo $result. "<br/>";
// 1050.50
setlocale(LC_MONETARY, 'tr_TR');
echo money_format('%!.2n', $result) ;
// 1.050,50
?>
To remove all but numbers, commas and full stops:
<?php
$prices = array( "1,00 €",
"€ 1.00",
"1'000,00 EUR",
"1 000.99$",
"1,000.01$",
"1.000,10 EURO");
$new_prices = array();
foreach ($prices as $price) {
$new_prices[] = preg_replace("/[^0-9,\.]/", "", $price);
}
print_r($new_prices);
Output:
Array ( [0] => 1,00 [1] => 1.00 [2] => 1000,00 [3] => 1000.99 [4] => 1,000.01 [5] => 1.000,10 )
Now lets utilize the parseFloat function from Michiel - php.net (I won't paste it here since it's a pretty big function):
<?php
$prices = array( "1,00 €",
"€ 1.00",
"1'000,00 EUR",
"1 000.99$",
"1,000.01$",
"1.000,10 EURO");
$new_prices = array();
foreach ($prices as $price) {
$new_prices[] = parseFloat(preg_replace("/[^0-9,\.]/", "", $price));
}
print_r($new_prices);
Output will be:
Array ( [0] => 1 [1] => 1 [2] => 1000 [3] => 1000.99 [4] => 1000.01 [5] => 1000.1 )
not perfect, but it work
function priceToFloat($s){
// clear witespaces
$s = trim($s);
$s = str_replace(' ', '', $s);
// is it minus value
$is_minus = false;
if(strpos($s, '(') !== false)
$is_minus = true;
if(strpos($s, '-') !== false)
$is_minus = true;
// check case where string has "," and "."
$dot = strpos($s, '.');
$semi = strpos($s, ',');
if($dot !== false && $semi !== false){
// change fraction sign to #, we change it again later
$s = str_replace('#', '', $s);
if($dot < $semi) $s = str_replace(',','#', $s);
else $s = str_replace('.','#', $s);
// remove another ",", "." and change "#" to "."
$s = str_replace([',','.', '#'], ['','', '.'], $s);
}
$s = str_replace(',', '.', $s);
// clear usless elements
$s = preg_replace("/[^0-9\.]/", "", $s);
// if it minus value put the "-" sign
if($is_minus) $s = -$s;
return (float) $s;
}
working cases
$prices = [
'123.456,789',
'123,456.789',
'123 456,789',
'123 456.789',
'-123,456.789',
'(123,456.789)',
];
foreach($prices as $price)
echo priceToFloat($price).'<br />';
return
123456.789
123456.789
123456.789
123456.789
-123456.789
-123456.789

Categories