PHP convert String number with whitespace to Float - php

I have a class with field price. It's stored in database as varchar(100) (don't ask me why, not my idea) and I have to retrieve it and divide it by the other price, which is also retrieved from database.
In database number looks like: 1 000.00 - thousands' parts are separated with whitespace (one million looks like ->1 000 000.00).
I try it on website: w3resource.com/php with an online interpreter.
What I do is...
$a = "3 999.99";
$b = "1 500.11";
$aa = floatval(str_replace(' ', '', $a));
$bb = floatval(str_replace(' ', '', $b));
$c = $aa - $bb;
echo $aa . ' - ' . $bb . ' = ' . $c;
and it displays correct output:
3999.99 - 1500.11 = 2499.88
But when I do it in my project, it's like:
$a = "3 999.99";
$b = "1 500.11";
$aa = floatval(str_replace(' ', '', $a));
$bb = floatval(str_replace(' ', '', $b));
$c = $aa - $bb;
echo $aa . ' - ' . $bb . ' = ' . $c;
3999.99 - 1500.11 = 2.00
In my project, price is truncated - everything that is after the whitespace is truncated and the calculations are performed only on the first digits, in my case it's: 3 - 1
Could anybody tell me where to look for a bug?

Most likely you have a non visible character as the thousand separator character. It's more safe to filter all characters except digits and . when sanitizing the input string. This can be achieved with the preg_replace function.
Your script can be modified to something like this:
$a = "3 999.99";
$b = "1 500.11";
$aa = floatval(preg_replace('/[^0-9.]/', '', $a));
$bb = floatval(preg_replace('/[^0-9.]/', '', $b));
$c = $aa - $bb;
echo $aa . ' - ' . $bb . ' = ' . $c;
Additionally, it's a bit dangerous and non exact to use floats when handling money in particular. Please have a look at this repository which helps a lot with this problem: https://github.com/moneyphp/money

The biggest mistake is price as varchar(100) - it's a string, it can be displayed in a million ways, but it cannot be recalculated. There are no excuses. It should be an integer or decimal and any subtraction should be done using SQL.
The second error is when you use a float as the value for price. Leave php float for astrophysicists, use int.
$a = "3 999.99";
$b = "1 500.11";
$a1 = (int) preg_replace('/[^0-9]/', '', $a);
$b1 = (int) preg_replace('/[^0-9]/', '', $b);
var_dump($a1, $b1); // test
echo'<hr>';
$c1 = $a1 - $b1;
var_dump($a1, $b1, $c1); // test
formatting to display:
echo substr_replace(substr_replace($c1,' ',-5,0), '.',-2,0);

Related

PHP 'NumberFormatter' 'SPELLOUT' is not providing required format in english

I Am using PHP NumberFormatter in my code to convert price value in words
for example, if it is rupees 125 then it should be 'One hundred and twenty five' instead of 'one hundred twenty five'.
I have tried the other examples like checking each digit unit value and replace the words
$numberFormatterClass = new \NumberFormatter("en", \NumberFormatter::SPELLOUT);
echo str_replace('-', ' ', $numberFormatterClass->format($number));
expecting for 125 = "One hundred and twenty five"
When the number is above 99 you can generate the spellout for the last two digits only. You then know where to insert the "and". In code:
$number = 125;
$numberFormatter = new \NumberFormatter('en', \NumberFormatter::SPELLOUT);
$fullSpellout = str_replace('-', ' ', $numberFormatter->format($number));
if ($number > 100) {
$lastTwoSpellout = str_replace('-', ' ', $numberFormatter->format(substr($number, -2)));
$hunderdsLength = strlen($fullSpellout) - strlen($lastTwoSpellout);
$fullSpellout = substr($fullSpellout, 0, $hunderdsLength) . 'and ' . $lastTwoSpellout;
}
echo $fullSpellout;
This outputs:
one hundred and twenty five
This is certainly not the only possible solution. There are many ways to insert the "and", and if the last two digits always generate two words you could also use that to detect where to insert the "and".
Here's a version based on words and using an array to insert the 'and':
$number = 125;
$numberFormatter = new \NumberFormatter('en', \NumberFormatter::SPELLOUT);
$spellout = str_replace('-', ' ', $numberFormatter->format($number));
if ($number > 100) {
$words = explode(' ', $spellout);
array_splice($words, -2, 0, ['and']);
$spellout = implode(' ', $words);
}
echo $spellout;

Modify decimal point and thousands separator without changing the number of decimals

I'm new to php and I'm trying to use number_format :
number_format ( float $number , int $decimals = 0 , string $dec_point = "." , string $thousands_sep = "," )
As in the title, my goal is to modify decimal point and thousands separator without changing the number of decimals as below:
$Num=123456.789;
$Num2=number_format ($Num, [decimals as in $Num], ",", "'" );
My result should be:
$Num2="123'456,789";
Edit
I need a code for an unknown number of decimals
You can use NumberFormatter.
You will still need to specify a certain amount of fraction digits, but you can just use a high enough value and be fine. It's not like the number of digits is really arbitrary. It's tied to your precision ini setting.
$formatter = new NumberFormatter("en_US", NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 42);
$formatter->setSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, "'");
$formatter->setSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL, ",");
echo $formatter->format(123456.7891234); // 123'456,7891234
Demo https://3v4l.org/TCAIA
You can do it such a way (firstly take a look to #Gordon answer – it's much more better):
<?php
function extendedNumberFormat($num, $decimalSeparator, $thousandSeparator) {
$asStr = strval($num);
$exploded = explode('.', $asStr);
$int = $exploded[0];
$decimal = isset($exploded[1]) ? $exploded[1] : null;
$result = number_format($int, 0, ".", $thousandSeparator);
if ($decimal !== null) {
$result .= $decimalSeparator . $decimal;
}
return $result;
}
echo extendedNumberFormat(123456.789, ',', "'") . "\n";
echo extendedNumberFormat(123456.7891, ',', "'") . "\n";
echo extendedNumberFormat(123456, ',', "'") . "\n";
//123'456,789
//123'456,7891
//123'456

VARCHAR SQL contains numbers how to get 2 decimals after comma

I'm having some trouble getting the price to show correct on my website. Currently i have a row VerkoopPP40 which is a VARCHAR input. In this row there is a price e.g. 89,5 or just 9. When I try to get these values it does some unexpected things.
**** Update ****
I've just tried this code:
<?php
function formatNumber($number, $format=[], $oldDecimalSeparator=",.·'", $multiplier=1)
{
if ($format) {
$format += ['numOfDecimals' => 0, 'decimalSeparator' => '.', 'thousandSeparator' => '']; # Default format
# Find decimal separator
# The decimal separator is the one that is the last and does not occur more than once
if ($letters = str_replace(' ', '', $number)) { # Replace spaces
if ($letters = preg_replace('/^-/', '', $letters)) { # Remove minus
if ($letters = preg_replace('/[0-9]/', '', $letters)) { # Get all non digits
$lastletter = substr($letters, -1); # Returns last char
if (substr_count($letters, $lastletter) == 1) {
if (strpos($oldDecimalSeparator, $lastletter) !== false)
$oldDecimalSep = $lastletter;
else
return $number;
}
}
}
}
$number = preg_replace('/[^0-9-]/', '', $number); # Remove all non digits except 'minus'
if ($oldDecimalSep)
$number = str_replace($oldDecimalSep, '.', $number); # Format to float
if ($multiplier != 1)
$number = $number * $multiplier;
# Convert float to new format
$number = number_format($number,
$format['numOfDecimals'],
$format['decimalSeparator'],
$format['thousandSeparator']
);
}
return $number;
}
This returns: 9,00 and 895,00 so the comma is in a different place right now. It's something I guess... Anyone got an idea to move the comma and remove a 0.
**** End Update ****
And echo-ed it like this:
<td><p>vanaf " . formatNumber($number, [
'numOfDecimals' => 2,
'decimalSeparator' => ',',
'thousandSeparator' => ' '
], ',.') . " p.p. <small>Excl btw</small></p></td>
If I just echo the VerkoopPP40 row it returns: €89,5 or €9.
So I googled around some and found this:
$var = $row["VerkoopPP40"];
$var = ltrim($var, '0');
$foo = $var;
$prijzen = number_format($foo, 2, ',', '');
This turns the . into a ,. But also returns €9,00 for the row that has 9 in it. But the strange thing is the row that has 89.5 in it now just returns €89,00. So somewhere in the code it rounds the numbers down.
Does anyone know how to get the price to show just €9,00 and €89,50 respectively.
I tried the following codes as well:
SELECT ROUND(VerkoopPP40,2) AS RoundedPrice
As database query. That didn't work.
$prijzen = CAST($prijzen as decimal(2,2));
Also didn't work. Any more ideas?
Don't know if this will help you, but found in the comments of the PHP doc : "To prevent the rounding that occurs when next digit after last significant decimal is 5 (mentioned by several people)..." read more
$num1 = "89,5";
$num2 = str_replace(',', '.', $num1);
$price = number_format($num2, 2, '.', '');
echo"[ $price ]";
you should use number_format but in the right way let me explain it to you
you tried this with 89.5
$prijzen = number_format($foo, 2, ',', '');
but this is written for 89,5 not for 89.5
//this will work for you
$var = $row["VerkoopPP40"];
echo 'raw output from database is :'.$var;
$var = $var / 10;
echo 'after this step the number is :'.$var;
$var = number_format($var, 2, '.', '');
echo 'after this step the number is :'.$var;
number_format(the input number, decimal places, 'the divider between whole numbers and decimals', '')

number format in php 999.99 [duplicate]

This question already has answers here:
Print numeric values to two decimal places
(6 answers)
How to pad single-digit numbers with a leading 0
(7 answers)
Closed 11 months ago.
Please help me with the number format in php
for example
I have some calculations, like a+b=c I want answer as 999.99 format in php I've read the number_format,sprintf but its not useful. please give me some useful ideas. My final result should be in 999.99 format.
Per the 'not useful' documentation:
$num = 999.98353;
$num = number_format($num, 2, '.', '');
If you take the time to actually read the documentation, there are pertinent examples.
In addition to number_format, you can use sprintf
$a = 999;
$b = .99;
$c = $a + $b;
echo sprintf('%03.2f', $c); // 999.99
$num = 999.98353;
$num1 = 10;
$num2 = $num + $num1;
echo number_format($num2, 2, '.', ''); // output 1009.98
try this
$a = 500.3755;
$b = 600.9855;
$c = $a + $b;
echo number_format($c, 2, '.', ''); //1101.36
echo number_format($c, 2, '.', ','); //1,101.36
$a = 1234.5678;
$b = 1234.5678;
$num = round(($a + $b), 2);
echo number_format($num, 2, '.', ',');
number_format works, try posting some of your codes.
You can use
$c = sprintf('%0.2f',$a)+sprintf('%0.2f',$b);
Or you can also try :
$c = $a+ $b; // If $c = 999.9999
$c = substr($c, 0, 2); // $c is now the string 999.9999
echo( number_format($c-1,2) ); // Will output 998.99

PHP String concatenation - "$a $b" vs $a . " " . $b - performance

Is there a speed difference between, say:
$newstring = "$a and $b went out to see $c";
and
$newstring = $a . " and " . $b . " went out to see " . $c;
and if so, why ?
Depending on the PHP version, it varies by how much the second is faster if you write it like:
$newstring = $a . ' and ' . $b . ' went out to see ' . $c;
PHP is very inconsistent from version to version and build to build when it comes to performance, you have to test it for yourself.
What nees to be said is that it also depends on the type of $a, $b and $c, as you can see below.
When you use ", PHP parses the string to see if there are any variable/placeholders used inside of it, but if you use only ' PHP treats it as a simple string without any further processing. So generally ' should be faster. At least in theory. In practice you must test.
Results(in seconds):
a, b, c are integers:
all inside " : 1.2370789051056
split up using " : 1.2362520694733
split up using ' : 1.2344131469727
a, b, c are strings:
all inside " : 0.67671513557434
split up using " : 0.7719099521637
split up using ' : 0.78600907325745 <--- this is always the slowest in the group. PHP, 'nough said
Using this code with Zend Server CE PHP 5.3:
<?php
echo 'a, b, c are integers:<br />';
$a = $b = $c = 123;
$t = xdebug_time_index();
for($i = 1000000; $i > 0; $i--)
$newstring = "$a and $b went out to see $c";
$t = xdebug_time_index() - $t;
echo 'all inside " : ', $t, '<br />';
$t = xdebug_time_index();
for($i = 1000000; $i > 0; $i--)
$newstring = $a . " and " . $b . " went out to see " . $c;
$t = xdebug_time_index() - $t;
echo 'split up using " : ', $t, '<br />';
$t = xdebug_time_index();
for($i = 1000000; $i > 0; $i--)
$newstring = $a . ' and ' . $b . ' went out to see ' . $c;
$t = xdebug_time_index() - $t;
echo 'split up using \' : ', $t, '<br /><br />a, b, c are strings:<br />';
$a = $b = $c = '123';
$t = xdebug_time_index();
for($i = 1000000; $i > 0; $i--)
$newstring = "$a and $b went out to see $c";
$t = xdebug_time_index() - $t;
echo 'all inside " : ', $t, '<br />';
$t = xdebug_time_index();
for($i = 1000000; $i > 0; $i--)
$newstring = $a . " and " . $b . " went out to see " . $c;
$t = xdebug_time_index() - $t;
echo 'split up using " : ', $t, '<br />';
$t = xdebug_time_index();
for($i = 1000000; $i > 0; $i--)
$newstring = $a . ' and ' . $b . ' went out to see ' . $c;
$t = xdebug_time_index() - $t;
echo 'split up using \' : ', $t, '<br />';
?>
There likely will be a speed difference, since it's two different syntaxes. What you need to ask is if the difference is important. In this case, no, I don't think you need to be worried. The difference would be too negligible.
I would recommend you doing whatever makes most sense to you visually. "$a and $b went out to see $c" can be a bit confusing when looking at it. If you wanted to go that route, I'd suggest curly-braces around your variables: "{$a} and {$b} went out to see {$c}".
I did a quick benchmark, and as others have said, the results were very inconsistent. I didn't notice any performance gain using single quotes instead of double ones. My guess is that it all comes down to preference.
You may want to stick to one type of quote for your coding style, and if you do, choose double quotes. The replacement feature comes in handy more often than you'd think.
I put the benchmark code on github.
If you're concerned about the speed of string concatenations at this level, you are using the wrong language. Compile an application in C for this use case and call that in your PHP script, if this really is a bottleneck.
Yes there is, however the difference is very negligible between
$newstring = "$a and $b went out to see $c";
and
$newstring = $a . " and " . $b . " went out to see " . $c;
If you used:
$newstring = $a . ' and ' . $b . ' went out to see ' . $c;
The difference would be slightly bigger (but probably still negligible), the reason for this is, if I recall correctly (I may be wrong on this), that PHP scans and parses the contents within double quotation marks for variables and special characters (\t, \n and so on) and when using single quotation marks it doesn't parse for variables or special characters, so there may be a slight increase in speed.
Why don't you test it, and compare the difference? Numbers don't lie, if you find that one performs better than the other, then you should ask why.
there is NO difference, period. ;)

Categories