How does .sprintf("%4.2f", value) function in PHP? - php

I'm working through some more PHP tutorials, specifically DevZone PHP 101, and am confused by:
echo .sprintf("%4.2f", (2 * $radius * pi()))
I found this
I think that means produce a floating-point field four positions wide with two decimal places, using the value of the first succeeding parameter.
That comes from the C/C++ line of programming languages. an sprintf() takes the first parameter as a format statement. Anything in it starting with a % is a field specifier; anything else is just printable text. So if you give a format statement with all text and no specifiers, it will print exactly the way it appears. With format specifiers, it needs data to work on.
But after trying some different values I'm still not getting it. It seems to me if the purpose of it in this case is just to limit the decimal to 2 places all I have to put is
.sprintf("%.2f", (2 * $radius * pi()))
What is the point of the 4 in the front of it? In the PHP Manual it leads me to believe it determines the total number of characters should be 4 but (a) thats not the case since the decimal point makes it 5 characters and (b) thats not the case because I tried changing it to a larger number like %8.2f and it didn't tack any zeros on to either end. Could someone please better explain this.
Thanks!

The first number %8.2f in the format specifier is for the filling length. Per default sprintf uses the space character.
You can see the effect with larger numbers:
printf("%20.2f", 1.23);
Will for example lead to:
1.23
There's 16 spaces before the number. The float takes up 4, and the fill length was set to 20 for instance. (Maybe you printed it out into the webpage, thus no padding spaces were visible..)
And there's an example further below on the sprintf manpage to use alternative padding characters:
printf("%'*20.2f", 1.23); // use the custom padding character '*'
Will result in:
****************1.23

Related

How to get NumberFormatter::parse() to only parse actual numeric strings?

I’m trying to parse some strings in some messed-up CSV files (about 100,000 rows per file). Some columns have been squished together in some rows, and I’m trying to get them unsquished back into their proper columns. Part of the logic needed there is to find whether a substring in a given colum is numeric or not.
Non-numeric strings can be anything, including strings that happen to begin with a number; numeric strings are generally written the European way, with dots used for thousand separators and commas for decimals, so without going through a bunch of string replacements, is_numeric() won’t do the trick:
\var_dump(is_numeric('3.527,25')); // bool(FALSE)
I thought – naïvely, it transpires – that the right thing to do would be to use NumberFormatter::parse(), but it seems that function doesn’t actually check whether the string given as a whole is parseable as a numeric string at all – instead it just starts at the beginning and when it reaches a character not allowed in a numeric string, cuts off the rest.
Essentially, what I’m looking for is something that will yield this:
$formatter = new \NumberFormatter('de-DE', \NumberFormatter::DECIMAL);
\var_dump($formatter->parse('3.527,25')); // float(3527.25)
\var_dump($formatter->parse('3thisisnotanumber')); // bool(FALSE)
But all I can get is this:
$formatter = new \NumberFormatter('de-DE', \NumberFormatter::DECIMAL);
\var_dump($formatter->parse('3.527,25')); // float(3527.25)
\var_dump($formatter->parse('3thisisnotanumber')); // float(3)
I figured perhaps the problem was that the LENIENT_PARSE attribute was set to true, but setting it to false ($formatter->setAttribute(\NumberFormatter::LENIENT_PARSE, 0)) has no effect; non-numeric strings still get parsed just fine as long as they begin with a number.
Since there are so many rows and each row may have as many as ten columns that need to be validated, I’m looking at upwards of a million validations per file – for that reason, I would prefer avoiding a preg_match()-based solution, since a million regex match calls would be quite expensive.
Is there some way to tell the NumberFormatter class that you would like it to please not be lenient and only treat the string as parseable if the entire string is numeric?
You can strip all the separators and check if whatever remains is a numeric value.
function customIsNumeric(string $value): bool
{
return is_numeric(str_replace(['.', ','], '', $value));
}
Live test available here.
You can use is_numeric() to check that it is only numbers before parsing. But NumberFormatter does not do what you are looking for here.

Two variables are not matching on PHP

So I have a string that for some reason, is returning as: 12×12. I did this in my code: utf8_decode($variant['size']) and received 12×12.
But this still isn't matching my string of 12x12
So I have 12×12 that is not showing as equal in php with: 12x12.
The X does look a little different but how do I fix this issue?
In 12×12 the × is the multiplication symbol, which obviously doesn't equate to x. Note that × doesn't reach the baseline in the text.
You should test for this multiplication symbol instead, if you can.

Reduce a MongoDB id into a shorter hash

I am looking for the best way to convert a MongoDB id 504aaedeff558cb507000004 into a shorter representation in PHP? Basically, users can reference id's in the app, and that long string is difficult.
The one caveat is, collisions should be 'rare'. Can we somehow get it down to 4, 5 or 6 characters?
Thanks.
While a hex digit can store 16 different states, a base64 encoded digit can store 64 different states, so you can store your whole MongoDB Id in 16 digits instead of 24 without losing any information:
print hexToBase64("50b3701de3de2a2416000000") . "\n"; # -> ULNwHePeKiQWAAAA
print base64ToHex("ULNwHePeKiQWAAAA") . "\n"; # -> 50b3701de3de2a2416000000
function base64ToHex($string) {
return bin2hex(base64_decode($string));
}
function hexToBase64($string) {
return base64_encode(hex2bin($string));
}
Your unique ID to start with can be mapped by [0-9a-f]. Shortening can be done in multiple ways - one easy way is to re-map character sets.
Our aim will be to cut the string size in two by replacing characters. A single character is one of 16, so two characters gives you 16^2 = 256 possibilities... I'm sure you know where I'm going with this. Take each couple of characters in your string, and calculate the mapping value. Generate the ASCII character corresponding, and use this instead. If you dislike having such an ugly ID at the end, base64-encode it - you'll get a string which is roughly 1/3 shorter than the one you started with.

php covert a Hexadecimal number 273ef9 into a path 27/3e/f9

As the title reads, what it is an effeicent way to covert a Hexadecimal number such as 273ef9 into a path such as 27/3e/f9 in PHP?
updated:::
actually, I want a unsual number convert to dexadecimal and furthr convert to a path....but may be we can skip the middle step.
How about combining a str_split with implode? Might not be super efficient but very readable:
implode('/',str_split("273ef9",2));
As a side note, this will of course work well with larger hex strings and can handle partial (3,5,7 in length) hex numbers (by just printing it as a single letter after the last slash).
Edit: With what you're asking now (decimal -> hex -> path), it would look like this:
$num = 2572025;
$hex = dechex($num);
implode('/',str_split($hex,2));
Of course, you can combine it for an even shorter but less readable representation:
implode('/',str_split(dechex($num),2));
The most efficient approach is to touch each character in the hex value exactly once, building up the string as you go. Because the string may have either an odd or even number of digits, you'll have to start with a check for this, outputting a single digit if it's an odd-length string. Then use a for loop to append groups of two digits, being careful with whether or not to add a slash. It will be a few lines of code.
Unless this code is being executed many millions of times, it probably isn't worth writing out this algorithm; Michael Petrov's is so readable and so nice. Go with this unless you have a real need to optimize.
By the way, to go from a decimal number to a hex string, just use dechex :)

printf function in PHP

I'm from a C background and understand basics of printf function.
I came across the follwing code
<?php
printf('%4$d %2$s code for %3$3.2f %1$s', "hours", "coders", 9, 99);
?>
which prints:
99 coders code for 9.00 hours
Can anyone help me in understanding the call to the printf function.
<n>$ means "use the nth argument, instead of whatever position you are in formatting specs".
The first argument of the printf function is a String that gets altered using the other arguments:
%4d - takes the 4th item after the comma and treats it as a decimal number
%2$s - takes the 2nd item after the comma and treats it as a String
%3$3.2f - takes the 3rd itam after the comma and treats it as a floating number with two decimal places
%1$s - takes the first item after the comma and treats it as a String
Ignacio's answer is correct.
One very useful application of this feature if you're using gettext for I18N. The order of substitution might change between one language and another. (though if you're wrapping stuff in calls to gettext, you'd be using sprintf).
I'm drawing a blank on a real-world example, guess I don't speak enough natural languages.
I think some of the confusion might have been an error in the code:
%3$3.2f should read %3$.2f instead (but it works either way).
Not sure what the difficulty is, because it's fairly well documented in the manual:
The first argument is the format mask, subsequent arguments are values to insert into the format mask. Rules for masking are the same as in C. And like in C, output is sent directly to stdout

Categories