PHP money_format padded number grouping - php

Basically, I'm trying to output a bunch of numbers in a nicely aligned column formatted to look like so:
$##,###.##
$##,###.##
With the following code
setlocale(LC_MONETARY, 'en_US.utf8');
money_format('%=0(#5.2n',$sum)
it works EXCEPT when $sum is less than 1000. For example, with
$sum=1550.00;
(as expected) the above code outputs
$01,550.00
However, with
$sum=167.00;
the above snippet outputs
$000167.00
which, obviously, is not what I need. According to the documentation
Grouping separators will not be applied to fill characters, even if the fill character is a digit.
So, this is the expected behaviour of the function. Doesn't seem to make sense, but that's how it works.
Any suggestions on how to get proper formatting for padded numbers would be appreciated.
Thanks!

You could build your own formatting function. localeconv() will give you data like separators and where the currency symbol should sit. This is one I used, which fit my needs:
function my_number_format($amount) {
// Get separators
$l = localeconv();
$str = number_format($amount, 2, $l['decimal_point'], $l['thousands_sep']);
// manual padding
while (strlen(preg_replace('/[^0-9]/', '', $str)) < 10) {
$init = preg_replace('/[^0-9].*/', '', $str); // initial all-digit sequence
$str = '0' . (strlen($init) == 3 ? $l['thousands_sep'] : '') . $str;
}
return $amount;
}

Related

PHP detect variable length string contains any character other than 1

Using PHP I sometimes have strings that look like the following:
111
110
011
1111
0110012
What is the most efficient way (preferably without regex) to determine if a string contains any character other then the character 1?
Here's a one-line code solution that can be put into a conditional etc.:
strlen(str_replace('1','',$mystring))==0
It strips out the "1"s and sees if there's anything left.
User Don't Panic commented that str_replace could be replaced by trim:
strlen(trim($mystring, '1'))==0
which removes leading and trailing 1s and sees if there's anything left. This would work for the particular case in OP's request but the first option will also tell you how many non-"1" characters you have (if that information matters). Depending on implementation, trim might run slightly faster because PHP doesn't have to check any characters between the first and last non-"1" characters.
You could also use a string like a character array and iterate through from the beginning until you find a character which is not =='1' (in which case, return true) or reach the end of the array (in which case, return false).
Finally, though OP here said "preferably without regex," others open to regexes might use one:
preg_match("/[^1]/", $mystring)==1
Another way to do it:
if (base_convert($string, 2, 2) === $string) {
// $string has only 0 and 1 characters.
}
since your $string is basically a binary number, you can check it with base_convert.
How it works:
var_dump(base_convert('110', 2, 2)); // 110
var_dump(base_convert('11503', 2, 2)); // 110
var_dump(base_convert('9111111111111111111110009', 2, 2)); // 11111111111111111111000
If the returned value of base_convert is different from the input, there're something other characters, beside 0 and 1.
If you want checks if the string has only 1 characters:
if(array_sum(str_split($string)) === strlen($string)) {
// $string has only 1 characters.
}
You retrieve all the single numbers with str_split, and sum them with array_sum. If the result isn't the same as the length of the string, then you've other number in the string beside 1.
Another option is treat string like array of symbols and check for something that is not 1. If it is - break for loop:
for ($i = 0; $i < strlen($mystring); $i++) {
if ($mystring[$i] != '1') {
echo 'FOUND!';
break;
}
}

Weird whitespace error in PHP

I have phone numbers that I want to format
And I have a pattern matcher that breaks down the numbers into a 10 digit format, and then applies dashes.
It works most of the time. However Im having an issue with certain numbers.
$trimmed = trim(preg_replace('/\s+/', '', $v->cust_num));
$tendigit = str_replace(array( '(', ')','-',' ' ), '', $trimmed);
$num = substr($tendigit,0,3)."-".substr($tendigit,3,3)."-".substr($tendigit,6,4);
This will change (555)555 5555, or 555-555 5555 or 5555555555 or (555)-555-5555 or 555-555-5555
to my format of 555-555-5555
However, I came across a few entries in my database, that dont seem to want to change.
One of the bad entries is this one. It contains two white spaces infront of the 4.
4-035-0100
When it runs through $trimmed, and I output $tendigit...it outputs
40350100
as expected. But then when I apply $num to it. It goes back to
4-035-0100
I would at least expect it to be
403-501-00
It seems there is some hidden whitespace in it, that my preg_replace, trim, and str_replace are not attacking.
Any ideas??
Thanks
The code below works, I have tried it with the special characters we discovered in the comments. Basically, the regex removes everything that isnt a number (0-9) and then uses your original formatting.
$trimmed = preg_replace('/\D+/', '', $v->cust_num);
$num = substr($trimmed,0,3)."-".substr($trimmed,3,3)."-".substr($trimmed,6,4);
You can condense your code a little:
$tendigit = preg_replace('/[^\d]/', '', $v->cust_num);
$num = substr($tendigit,0,3)."-".substr($tendigit,3,3)."-".substr($tendigit,6,4);
Though, you should add in some conditions to check that the phone number actually has 10 digits too:
$tendigit = preg_replace('/[^\d]/', '', $v->cust_num);
if(strlen($tendigit == 10)){
$num = substr($tendigit,0,3)."-".substr($tendigit,3,3)."-".substr($tendigit,6,4);
} else {
// catch your error here, eg 'please enter 10 digits'
}
The first line removes any 'non-digit' [^\d].
The conditional statement checks if the $tendigit variable has 10 digits in it.
If it does, then it uses your code to parse and format.
If it doesnt, then you can catch an error.

PHP Strip String, Convert to int

I have a STRING $special which is formatted like £130.00 and is also an ex TAX(VAT) price.
I need to strip the first char so i can run some simple addition.
$str= substr($special, 1, 0); // Strip first char '£'
echo $str ; // Echo Value to check its worked
$endPrice = (0.20*$str)+$str ; // Work out VAT
I don't receive any value when i echo on the second line ? Also would i then need to convert the string to an integer in order to run the addition ?
Thanks
Matt
+++ UPDATE
Thanks for your help with this, I took your code and added some of my own, There are more than likely nicer ways to do this but it works :) I found out that if the price was below 1000 would look like £130.00 if the price was a larger value it would include a break. ie £1,400.22.
$str = str_replace('£', '', $price);
$str2 = str_replace(',', '', $str);
$vatprice = (0.2 * $str2) + $str2;
$display_vat_price = sprintf('%0.2f', $vatprice);
echo "£";
echo $display_vat_price ;
echo " (Inc VAT)";
Thanks again, Matt
You cannot use substr the way you are using it currently. This is because you are trying to remove the £ char, which is a two-byte unicode character, but substr() isn't unicode safe. You can either use $str = substr($string, 2), or, better, str_replace() like this:
$string = '£130.00';
$str = str_replace('£', '', $string);
echo (0.2 * $str) + $str; // 156
Original answer
I'll keep this version as it still can give some insight. The answer would be OK if £ wouldn't be a 2byte unicode character. Knowing this, you can still use it but you need to start the sub-string at offset 2 instead of 1.
Your usage of substr is wrong. It should be:
$str = substr($special, 1);
Check the documentation the third param would be the length of the sub-string. You passed 0, therefore you got an empty string. If you omit the third param it will return the sub-string starting from the index given in the first param until the end of the original string.

php find numbers in a string after and before the word "euro"

I have a string like "9 mesi in cotone EURO 3+ss" or "9 mesi in cotone 3 EURO +ss" and I would like to get the integer value before or after the word EURO, depends on string format (I don't know how the user will send it)
Can anyone help me, please?
Something like this:
if(preg_match('/(\\d+(?:\.\\d+)?)?\\s*euro\\s*(\\d+(?:\.\\d+)?)?/i', $string, $regs) and count($regs) > 1) {
if(!$regs[1] and !$regs[2]) {
// Invalid input
} else {
$amount = floatval($regs[1] ? $regs[1] : $regs[2]);
// Do something with $amount
}
}
The regular expression may need to be adjusted depending on the locale (space thousand separators, commas, etc).
If working with integer values, the regex simplifies to:
preg_match('/(\\d+)?\\s*euro\\s*(\\d+)?/i', $string, $regs)
preg_match_all('/[0-9]+/',$string,$matches);
$values = array_shift($matches);
$lastnum = array_pop($values);
echo $lastnum;
It might be simpler to break it up into two regexes:
/(d+)\s*EURO/
/EURO\s*(d+)/
This should set you on the right track.

How to add currency strings (non-standardized input) together in PHP?

I have a form in which people will be entering dollar values.
Possible inputs:
$999,999,999.99
999,999,999.99
999999999
99,999
$99,999
The user can enter a dollar value however they wish. I want to read the inputs as doubles so I can total them.
I tried just typecasting the strings to doubles but that didn't work. Total just equals 50 when it is output:
$string1 = "$50,000";
$string2 = "$50000";
$string3 = "50,000";
$total = (double)$string1 + (double)$string2 + (double)$string3;
echo $total;
A regex won't convert your string into a number. I would suggest that you use a regex to validate the field (confirm that it fits one of your allowed formats), and then just loop over the string, discarding all non-digit and non-period characters. If you don't care about validation, you could skip the first step. The second step will still strip it down to digits and periods only.
By the way, you cannot safely use floats when calculating currency values. You will lose precision, and very possibly end up with totals that do not exactly match the inputs.
Update: Here are two functions you could use to verify your input and to convert it into a decimal-point representation.
function validateCurrency($string)
{
return preg_match('/^\$?(\d{1,3})(,\d{3})*(.\d{2})?$/', $string) ||
preg_match('/^\$?\d+(.\d{2})?$/', $string);
}
function makeCurrency($string)
{
$newstring = "";
$array = str_split($string);
foreach($array as $char)
{
if (($char >= '0' && $char <= '9') || $char == '.')
{
$newstring .= $char;
}
}
return $newstring;
}
The first function will match the bulk of currency formats you can expect "$99", "99,999.00", etc. It will not match ".00" or "99.", nor will it match most European-style numbers (99.999,00). Use this on your original string to verify that it is a valid currency string.
The second function will just strip out everything except digits and decimal points. Note that by itself it may still return invalid strings (e.g. "", "....", and "abc" come out as "", "....", and ""). Use this to eliminate extraneous commas once the string is validated, or possibly use this by itself if you want to skip validation.
You don't ever want to represent monetary values as floats!
For example, take the following (seemingly straight forward) code:
$x = 1.0;
for ($ii=0; $ii < 10; $ii++) {
$x = $x - .1;
}
var_dump($x);
You might assume that it would produce the value zero, but that is not the case. Since $x is a floating point, it actually ends up being a tiny bit more than zero (1.38777878078E-16), which isn't a big deal in itself, but it means that comparing the value with another value isn't guaranteed to be correct. For example $x == 0 would produce false.
http://p2p.wrox.com/topic.asp?TOPIC_ID=3099
goes through it step by step
[edit] typical...the site seems to be down now... :(
not a one liner, but if you strip out the ','s you can do: (this is pseudocode)
m/^\$?(\d+)(?:\.(\d\d))?$/
$value = $1 + $2/100;
That allows $9.99 but not $9. or $9.9 and fails to complain about missplaced thousands separators (bug or feature?)
There is a potential 'locality' issue here because you are assuming that thousands are done with ',' and cents as '.' but in europe it is opposite (e.g. 1.000,99)
I recommend not to use a float for storing currency values. You can get rounding errors if the sum gets large. (Ok, if it gets very large.)
Better use an integer variable with a large enough range, and store the input in cents, not dollars.
I belive that you can accomplish this with printf, which is similar to the c function of the same name. its parameters can be somewhat esoteric though. you can also use php's number_format function
Assuming that you are getting real money values, you could simply strip characters that are not digits or the decimal point:
(pseudocode)
newnumber = replace(oldnumber, /[^0-9.]/, //)
Now you can convert using something like
double(newnumber)
However, this will not take care of strings such as "5.6.3" and other such non-money strings. Which raises the question, "Do you need to handle badly formatted strings?"

Categories