With printf() and sprintf() functions, escape character is not backslash '\' but rather '%'.
Ie. to print '%' character you need to escape it with itself:
<?php
printf('%%%s%%', 'koko'); #output: '%koko%'
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
sprintf — フォーマットされた文字列を返す
format
0個以上のディレクティブで構成されるフォーマット文字列:
変換結果に直接コピーされる通常文字列 (%
は除きます)
と、変換仕様。
これらのいずれも、自分が持つパラメータを取得します。
変換の仕様は、以下のプロトタイプに従います:
%[argnum$][flags][width][.precision]specifier
.
何番目の引数を変換の対象にするかを指定するために、
数値の後にドル記号 $
を続けます。
フラグ | 説明 |
---|---|
- |
与えられたフィールドの幅を左寄せにします。 右寄せがデフォルトです。 |
+ |
正の数値の前に付ける + 符号です;
デフォルトは、負の数にだけマイナスの符号が数値の前に付きます。
|
(space) |
スペースに変換される詰め物です。 これがデフォルトです。 |
0 |
数値の左側を0埋めします。
s 指定子を使うと、
右側にも0埋めできます。
|
' (char) |
指定された (char) で埋めます。 |
(最小で)何文字がこの変換結果に含まれるかを数値で指定するか、
*
を指定します。
*
を指定した場合、
指定子によってフォーマットされる値の前に、
幅を追加の数値として指定します。
ピリオド .
の後に数値を続けるか、
*
を続けますが、
その意味は指定子に依存します:
e
, E
,
f
と F
指定子の場合:
小数点の後に表示する桁数 (デフォルトでは、この値は6です)
g
, G
,
h
, H
指定子の場合:
表示する最大の有効桁数
s
指定子の場合:
文字列を切り捨てる時点、つまり、文字列の最大の長さを設定します。
注意: 明示的に精度を指定せず、ピリオドを指定した場合、精度は0として扱われます。
*
を使った場合、 精度は指定子によってフォーマットされる値の前に、 追加の数値として指定します。
指定子 | 説明 |
---|---|
% |
文字通り、パーセント文字です。 引数は不要です。 |
b |
引数は整数として扱われ、バイナリ値として表現されます。 |
c |
引数は整数として扱われ、ASCII文字として表現されます。 |
d |
引数は整数として扱われ、(符号付き)10進数値として表現されます。 |
e |
引数は科学的記法で表現された値(e.g. 1.2e+2)として扱われます。 |
E |
e 指定子に似ていますが、
大文字を使います(e.g. 1.2E+2)
|
f |
引数は小数として扱われ、浮動小数点数値として表現されます(ロケールを考慮します)。 |
F |
引数は小数として扱われ、浮動小数点数値として表現されます(ロケールを考慮しません)。 |
g |
汎用フォーマット
P を精度を表す、ゼロでない値とします。
精度が省略された場合、Pの値は6です。
精度に0を指定した場合、Pの値は1になります。
この場合、
P > X ≥ −4 の場合、 |
G |
g 指定子に似ていますが、
E と f を使います。
|
h |
g 指定子に似ていますが、
F を使います。
PHP 8.0.0 以降で利用可能です。
|
H |
g 指定子に似ていますが、
E と F を使います。
PHP 8.0.0 以降で利用可能です。
|
o |
引数は整数として扱われ、8進数値として表現されます。 |
s |
引数は文字列として扱われ、文字列として表現されます。 |
u |
引数は整数として扱われ、符号なし10進数値として表現されます。 |
x |
引数は整数として扱われ、16進数値(小文字)として表現されます。 |
X |
引数は整数として扱われ、16進数値(大文字)として表現されます。 |
c
指定子はパディングと幅を無視します
文字列と width 指定子を、1文字の表現に1バイト以上必要な文字セットと一緒に使おうとすると、 期待しない結果になるかもしれません。
値は、指定子の型に合うように強制されます:
型 | 指定子 |
---|---|
string | s |
int |
d ,
u ,
c ,
o ,
x ,
X ,
b
|
float |
e ,
E ,
f ,
F ,
g ,
G ,
h ,
H
|
values
フォーマット文字列 format
に基づき生成された文字列を返します。
PHP 8.0.0 以降では、
引数の数が0の場合に ValueError
がスローされます。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
PHP 8.0.0 以降では、
[width]
の値が0より小さかったり、
PHP_INT_MAX
より大きい場合に、
ValueError がスローされます。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
PHP 8.0.0 以降では、
[precision]
の値が0より小さかったり、
PHP_INT_MAX
より大きい場合に、
ValueError がスローされます。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
PHP 8.0.0 以降では、
引数が必要な数より少なかった場合、
ArgumentCountError
がスローされます。
これより前のバージョンでは、代わりに false
を返し、E_WARNING
を発生させていました。
バージョン | 説明 |
---|---|
8.0.0 |
この関数は、失敗時に false を返さなくなりました。
|
8.0.0 |
引数の数が0だった場合、
ValueError がスローされるようになりました。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
|
8.0.0 |
[width] の値が0より小さかったり、
PHP_INT_MAX より大きい場合に、
ValueError をスローするようになりました。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
|
8.0.0 |
[precision] の値が0より小さかったり、
PHP_INT_MAX より大きい場合に、
ValueError をスローするようになりました。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
|
8.0.0 |
引数が必要な数より少なかった場合、
ArgumentCountError
がスローされるようになりました。
これより前のバージョンでは、代わりに E_WARNING
を発生させていました。
|
例1 引数の交換
フォーマット文字列における引数の 番号付け/交換 をサポートしています。以下に例を示します。
<?php
$num = 5;
$location = 'tree';
$format = 'There are %d monkeys in the %s';
echo sprintf($format, $num, $location);
?>
上の例の出力は以下となります。
There are 5 monkeys in the tree
ここで、フォーマット文字列が別のファイルにある場合を考えてみましょう。 これは、出力を国際化したりする場合に行われる可能性があります。 たとえばフォーマット文字列が次のように書き換えられたとすると、
<?php
$format = 'The %s contains %d monkeys';
echo sprintf($format, $num, $location);
?>
ここで、問題が発生します。フォーマット文字列における置換指示子の順番は、 コードにおける引数の順番と一致していません。 だからといってコードを変更するのではなく、 むしろ置換指示子が参照するフォーマット文字列のほうで指示を行う方が望ましいでしょう。 フォーマット文字列を次のように書き換えてみましょう。
<?php
$format = 'The %2$s contains %1$d monkeys';
echo sprintf($format, $num, $location);
?>
こうすることによるもうひとつの利点は、 同じ置換指示子を複数回使用する際にコードに引数を追加せずにすむことです。 例えば、次のようになります。
<?php
$format = 'The %2$s contains %1$d monkeys.
That\'s a nice %2$s full of %1$d monkeys.';
echo sprintf($format, $num, $location);
?>
引数の交換を使うときには、
位置指定子 n$
をパーセント記号 (%
) の直後に置かなければならず、
間に他の指定を入れてはいけません。次の例を示します。
例2 埋める文字を指定する
<?php
echo sprintf("%'.9d\n", 123);
echo sprintf("%'.09d\n", 123);
?>
上の例の出力は以下となります。
......123 000000123
例3 位置指定子と他の指定との共用
<?php
$format = 'The %2$s contains %1$04d monkeys';
echo sprintf($format, $num, $location);
?>
上の例の出力は以下となります。
The tree contains 0005 monkeys
例4 sprintf(): ゼロ埋めされた数値
<?php
$isodate = sprintf("%04d-%02d-%02d", $year, $month, $day);
?>
例5 sprintf(): 通貨フォーマット
<?php
$money1 = 68.75;
$money2 = 54.35;
$money = $money1 + $money2;
echo $money;
echo "\n";
$formatted = sprintf("%01.2f", $money);
echo $formatted;
?>
上の例の出力は以下となります。
123.1 123.10
例6 sprintf(): 科学的記法
<?php
$number = 362525200;
echo sprintf("%.3e", $number);
?>
上の例の出力は以下となります。
3.625e+8
With printf() and sprintf() functions, escape character is not backslash '\' but rather '%'.
Ie. to print '%' character you need to escape it with itself:
<?php
printf('%%%s%%', 'koko'); #output: '%koko%'
?>
1. A plus sign ('+') means put a '+' before positive numbers while a minus sign ('-') means left justify. The documentation incorrectly states that they are interchangeable. They produce unique results that can be combined:
<?php
echo sprintf ("|%+4d|%+4d|\n", 1, -1);
echo sprintf ("|%-4d|%-4d|\n", 1, -1);
echo sprintf ("|%+-4d|%+-4d|\n", 1, -1);
?>
outputs:
| +1| -1|
|1 |-1 |
|+1 |-1 |
2. Padding with a '0' is different than padding with other characters. Zeros will only be added at the front of a number, after any sign. Other characters will be added before the sign, or after the number:
<?php
echo sprintf ("|%04d|\n", -2);
echo sprintf ("|%':4d|\n", -2);
echo sprintf ("|%-':4d|\n", -2);
// Specifying both "-" and "0" creates a conflict with unexpected results:
echo sprintf ("|%-04d|\n", -2);
// Padding with other digits behaves like other non-zero characters:
echo sprintf ("|%-'14d|\n", -2);
echo sprintf ("|%-'04d|\n", -2);
?>
outputs:
|-002|
|::-2|
|-2::|
|-2 |
|-211|
|-2 |
Here is how to print a floating point number with 16 significant digits regardless of magnitude:
<?php
$result = sprintf(sprintf('%%.%dF', max(15 - floor(log10($value)), 0)), $value);
?>
This works more reliably than doing something like sprintf('%.15F', $value) as the latter may cut off significant digits for very small numbers, or prints bogus digits (meaning extra digits beyond what can reliably be represented in a floating point number) for very large numbers.
There are already some comments on using sprintf to force leading leading zeros but the examples only include integers. I needed leading zeros on floating point numbers and was surprised that it didn't work as expected.
Example:
<?php
sprintf('%02d', 1);
?>
This will result in 01. However, trying the same for a float with precision doesn't work:
<?php
sprintf('%02.2f', 1);
?>
Yields 1.00.
This threw me a little off. To get the desired result, one needs to add the precision (2) and the length of the decimal seperator "." (1). So the correct pattern would be
<?php
sprintf('%05.2f', 1);
?>
Output: 01.00
Please see http://stackoverflow.com/a/28739819/413531 for a more detailed explanation.
Here's a clean, working version of functions to allow using named arguments instead of numeric ones. ex: instead of sprintf('%1$s', 'Joe');, we can use sprintf('%name$s', array('name' => 'Joe'));. I've provided 2 different versions: the first uses the php-like syntax (ex: %name$s), while the second uses the python syntax (ex: %(name)s).
<?php
/**
* version of sprintf for cases where named arguments are desired (php syntax)
*
* with sprintf: sprintf('second: %2$s ; first: %1$s', '1st', '2nd');
*
* with sprintfn: sprintfn('second: %second$s ; first: %first$s', array(
* 'first' => '1st',
* 'second'=> '2nd'
* ));
*
* @param string $format sprintf format string, with any number of named arguments
* @param array $args array of [ 'arg_name' => 'arg value', ... ] replacements to be made
* @return string|false result of sprintf call, or bool false on error
*/
function sprintfn ($format, array $args = array()) {
// map of argument names to their corresponding sprintf numeric argument value
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
// find the next named argument. each search starts at the end of the previous replacement.
for ($pos = 0; preg_match('/(?<=%)([a-zA-Z_]\w*)(?=\$)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
$arg_pos = $match[0][1];
$arg_len = strlen($match[0][0]);
$arg_key = $match[1][0];
// programmer did not supply a value for the named argument found in the format string
if (! array_key_exists($arg_key, $arg_nums)) {
user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
return false;
}
// replace the named argument with the corresponding numeric one
$format = substr_replace($format, $replace = $arg_nums[$arg_key], $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace); // skip to end of replacement for next iteration
}
return vsprintf($format, array_values($args));
}
/**
* version of sprintf for cases where named arguments are desired (python syntax)
*
* with sprintf: sprintf('second: %2$s ; first: %1$s', '1st', '2nd');
*
* with sprintfn: sprintfn('second: %(second)s ; first: %(first)s', array(
* 'first' => '1st',
* 'second'=> '2nd'
* ));
*
* @param string $format sprintf format string, with any number of named arguments
* @param array $args array of [ 'arg_name' => 'arg value', ... ] replacements to be made
* @return string|false result of sprintf call, or bool false on error
*/
function sprintfn ($format, array $args = array()) {
// map of argument names to their corresponding sprintf numeric argument value
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
// find the next named argument. each search starts at the end of the previous replacement.
for ($pos = 0; preg_match('/(?<=%)\(([a-zA-Z_]\w*)\)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
$arg_pos = $match[0][1];
$arg_len = strlen($match[0][0]);
$arg_key = $match[1][0];
// programmer did not supply a value for the named argument found in the format string
if (! array_key_exists($arg_key, $arg_nums)) {
user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
return false;
}
// replace the named argument with the corresponding numeric one
$format = substr_replace($format, $replace = $arg_nums[$arg_key] . '$', $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace); // skip to end of replacement for next iteration
}
return vsprintf($format, array_values($args));
}
?>
Be cafeful while trying to refactor longer strings with repeated placeholders like
sprintf("Hi %s. Your name is %s", $name, $name);
to use argument numbering:
sprintf("Hi %1$s. Your name is %1$s", $name);
This will nuke you at **runtime**, because of `$s` thing being handled as variable. If you got no $s for substitution, notice will be thrown.
The solution is to use single quotes to prevent variable substitution in string:
sprintf('Hi %1$s. Your name is %1$s', $name);
If you need variable substitution, then you'd need to split your string to keep it in single quotes:
sprintf("Hi " . '%1$s' . ". Your {$variable} is " . '%1$s', $name);
I had a nightmare trying to find the two's complement of a 32 bit number.
I got this from http://www.webmasterworld.com/forum88/13334.htm (credit where credit is due... =P )
Quote: ...find out the 2's complement of any number, which is -(pow(2, n) - N) where n is the number of bits and N is the number for which to find out its 2's complement.
This worked magic for me... previously I was trying to use
sprintf ("%b",$32BitDecimal);
But it always returned 10000000000000000000000 when the $32BitDecimal value got above 2,000,000,000.
This -(pow(2, n) - N)
Worked remarkably well and was very accurate.
Hope this helps someone fighting with two's complement in PHP.
Just to elaborate on downright's point about different meanings for %f, it appears the behavior changed significantly as of 4.3.7, rather than just being different on different platforms. Previously, the width specifier gave the number of characters allowed BEFORE the decimal. Now, the width specifier gives the TOTAL number of characters. (This is in line with the semantics of printf() in other languages.) See bugs #28633 and #29286 for more details.
The old "monkey" example which helped me a lot has sadly disappeared.
I'll Re-post it in comment as a memory.
<?php
$n = 43951789;
$u = -43951789;
$c = 65; // ASCII 65 is 'A'
// notice the double %%, this prints a literal '%' character
printf("%%b = '%b'\n", $n); // binary representation
printf("%%c = '%c'\n", $c); // print the ascii character, same as chr() function
printf("%%d = '%d'\n", $n); // standard integer representation
printf("%%e = '%e'\n", $n); // scientific notation
printf("%%u = '%u'\n", $n); // unsigned integer representation of a positive integer
printf("%%u = '%u'\n", $u); // unsigned integer representation of a negative integer
printf("%%f = '%f'\n", $n); // floating point representation
printf("%%o = '%o'\n", $n); // octal representation
printf("%%s = '%s'\n", $n); // string representation
printf("%%x = '%x'\n", $n); // hexadecimal representation (lower-case)
printf("%%X = '%X'\n", $n); // hexadecimal representation (upper-case)
printf("%%+d = '%+d'\n", $n); // sign specifier on a positive integer
printf("%%+d = '%+d'\n", $u); // sign specifier on a negative integer
/*
%b = '10100111101010011010101101'
%c = 'A'
%d = '43951789'
%e = '4.395179e+7'
%u = '43951789'
%u = '18446744073665599827'
%f = '43951789.000000'
%o = '247523255'
%s = '43951789'
%x = '29ea6ad'
%X = '29EA6AD'
%+d = '+43951789'
%+d = '-43951789'
*/
$s = 'monkey';
$t = 'many monkeys';
printf("[%s]\n", $s); // standard string output
printf("[%10s]\n", $s); // right-justification with spaces
printf("[%-10s]\n", $s); // left-justification with spaces
printf("[%010s]\n", $s); // zero-padding works on strings too
printf("[%'#10s]\n", $s); // use the custom padding character '#'
printf("[%10.10s]\n", $t); // left-justification but with a cutoff of 10 characters
/*
[monkey]
[ monkey]
[monkey ]
[0000monkey]
[####monkey]
[many monke]
*/
?>
A more complete and working version of mb_sprintf and mb_vsprintf. It should work with any "ASCII preserving" encoding such as UTF-8 and all the ISO-8859 charsets. It handles sign, padding, alignment, width and precision. Argument swapping is not handled.
<?php
if (!function_exists('mb_sprintf')) {
function mb_sprintf($format) {
$argv = func_get_args() ;
array_shift($argv) ;
return mb_vsprintf($format, $argv) ;
}
}
if (!function_exists('mb_vsprintf')) {
/**
* Works with all encodings in format and arguments.
* Supported: Sign, padding, alignment, width and precision.
* Not supported: Argument swapping.
*/
function mb_vsprintf($format, $argv, $encoding=null) {
if (is_null($encoding))
$encoding = mb_internal_encoding();
// Use UTF-8 in the format so we can use the u flag in preg_split
$format = mb_convert_encoding($format, 'UTF-8', $encoding);
$newformat = ""; // build a new format in UTF-8
$newargv = array(); // unhandled args in unchanged encoding
while ($format !== "") {
// Split the format in two parts: $pre and $post by the first %-directive
// We get also the matched groups
list ($pre, $sign, $filler, $align, $size, $precision, $type, $post) =
preg_split("!\%(\+?)('.|[0 ]|)(-?)([1-9][0-9]*|)(\.[1-9][0-9]*|)([%a-zA-Z])!u",
$format, 2, PREG_SPLIT_DELIM_CAPTURE) ;
$newformat .= mb_convert_encoding($pre, $encoding, 'UTF-8');
if ($type == '') {
// didn't match. do nothing. this is the last iteration.
}
elseif ($type == '%') {
// an escaped %
$newformat .= '%%';
}
elseif ($type == 's') {
$arg = array_shift($argv);
$arg = mb_convert_encoding($arg, 'UTF-8', $encoding);
$padding_pre = '';
$padding_post = '';
// truncate $arg
if ($precision !== '') {
$precision = intval(substr($precision,1));
if ($precision > 0 && mb_strlen($arg,$encoding) > $precision)
$arg = mb_substr($precision,0,$precision,$encoding);
}
// define padding
if ($size > 0) {
$arglen = mb_strlen($arg, $encoding);
if ($arglen < $size) {
if($filler==='')
$filler = ' ';
if ($align == '-')
$padding_post = str_repeat($filler, $size - $arglen);
else
$padding_pre = str_repeat($filler, $size - $arglen);
}
}
// escape % and pass it forward
$newformat .= $padding_pre . str_replace('%', '%%', $arg) . $padding_post;
}
else {
// another type, pass forward
$newformat .= "%$sign$filler$align$size$precision$type";
$newargv[] = array_shift($argv);
}
$format = strval($post);
}
// Convert new format back from UTF-8 to the original encoding
$newformat = mb_convert_encoding($newformat, $encoding, 'UTF-8');
return vsprintf($newformat, $newargv);
}
}
?>
If you use the default padding specifier (a space) and then print it to HTML, you will notice that HTML does not display the multiple spaces correctly. This is because any sequence of white-space is treated as a single space.
To overcome this, I wrote a simple function that replaces all the spaces in the string returned by sprintf() with the character entity reference " " to achieve non-breaking space in strings returned by sprintf()
<?php
//Here is the function:
function sprintf_nbsp() {
$args = func_get_args();
return str_replace(' ', ' ', vsprintf(array_shift($args), array_values($args)));
}
//Usage (exactly like sprintf):
$format = 'The %d monkeys are attacking the [%10s]!';
$str = sprintf_nbsp($format, 15, 'zoo');
echo $str;
?>
The above example will output:
The 15 monkeys are attacking the [ zoo]!
<?php
//The variation that prints the string instead of returning it:
function printf_nbsp() {
$args = func_get_args();
echo str_replace(' ', ' ', vsprintf(array_shift($args), array_values($args)));
}
?>
To jrust at rustyparts.com, note that if you're using a double-quoted string and *don't* escape the dollar sign with a backslash, $s and $d will be interpreted as variable references. The backslash isn't part of the format specifier itself but you do need to include it when you write the format string (unless you use single quotes).
If you want to convert a decimal (integer) number into constant length binary number in lets say 9 bits, use this:
$binary = sprintf('%08b', $number );
for example:
<?php
$bin = sprintf('%08b',511 );
echo $bin."\n";
?>
would output 111111111
And 2 would output 00000010
I know the leading zeros are useful to me, perhaps they are to someone else too.
Just a reminder for beginners : example 6 'printf("[%10s]\n", $s);' only works (that is, shows out the spaces) if you put the html '<pre></pre>' tags ( head-scraping time saver ;-).
Using argument swapping in sprintf() with gettext: Let's say you've written the following script:
<?php
$var = sprintf(gettext("The %2\$s contains %1\$d monkeys"), 2, "cage");
?>
Now you run xgettext in order to generate a .po file. The .po file will then look like this:
#: file.php:9
#, ycp-format
msgid "The %2\\$s contains %1\\$d monkeys"
msgstr ""
Notice how an extra backslash has been added by xgettext.
Once you've translated the string, you must remove all backslashes from the ID string as well as the translation, so the po file will look like this:
#: file.php:9
#, ycp-format
msgid "The %2$s contains %1$d monkeys"
msgstr "Der er %1$d aber i %2$s"
Now run msgfmt to generate the .mo file, restart Apache to remove the gettext cache if necessary, and you're off.
If you use argument numbering, then format specifications with the same number get the same argument; this can save repeating the argument in the function call.
<?php
$pattern = '%1$s %1$\'#10s %1$s!';
printf($pattern, "badgers");
?>
$format = 'There are %1$d monkeys in the %s and %s ';
printf($format, 100, 'Chennai', 'Bangalore');
Expecting to output
"There are 100 monkeys in the Chennai and bangalore"
But, this will output
"There are 100 monkeys in the 100 and Chennai"
Because, the second and Third specifiers takes 1rst and 2nd arguments. Because it is not assigned with any arguments.
And continuing on the same theme of a key-based sprintf...
I'm roughly (I can see a couple cases where it comes out wierd) copying the syntax of Python's string formatting with a dictionary. The improvement over the several past attempts is that this one still respects all of the formating options, as you can see in my example.
And the error handling is really crappy (just an echo). I just threw this together so do with it what you will. =]
<?php
function sprintf_array($string, $array)
{
$keys = array_keys($array);
$keysmap = array_flip($keys);
$values = array_values($array);
while (preg_match('/%\(([a-zA-Z0-9_ -]+)\)/', $string, $m))
{
if (!isset($keysmap[$m[1]]))
{
echo "No key $m[1]\n";
return false;
}
$string = str_replace($m[0], '%' . ($keysmap[$m[1]] + 1) . '$', $string);
}
array_unshift($values, $string);
var_dump($values);
return call_user_func_array('sprintf', $values);
}
echo sprintf_array('4 digit padded number: %(num)04d ', array('num' => 42));
?>
Cheers!
Encoding and decoding IP adress to format: 1A2B3C4D (mysql column: char(8) )
<?php
function encode_ip($dotquad_ip)
{
$ip_sep = explode('.', $dotquad_ip);
return sprintf('%02x%02x%02x%02x', $ip_sep[0], $ip_sep[1], $ip_sep[2], $ip_sep[3]);
}
function decode_ip($int_ip)
{
$hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
return hexdec($hexipbang[0]). '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
}
?>
I couldn't find what should be a WARNING in the documentation above, that if you have more specifiers than variables to match them sprintf returns NOTHING. This fact, IMHO, should also be noted under return values.
Note that when using the argument swapping, you MUST number every argument, otherwise sprintf gets confused. This only happens if you use number arguments first, then switch to a non-numbered, and then back to a numbered one.
<?php
$sql = sprintf( "select * from %1\$s left join %2\$s on( %1\$s.id = %2\$s.midpoint ) where %1\$s.name like '%%%s%%' and %2\$s.tagname is not null", "table1", "table2", "bob" );
// Wont work:
// Sprintf will complain about not enough arguments.
$sql = sprintf( "select * from %1\$s left join %2\$s on( %1\$s.id = %2\$s.midpoint ) where %1\$s.name like '%%%3\$s%%' and %2\$s.tagname is not null", "table1", "table2", "bob" );
// Will work: note the %3\$s
?>
Note that when using a sign specifier, the number zero is considered positive and a "+" sign will be prepended to it.
<?php
printf('%+d', 0); // +0
?>
Just wanted to add that to get the remaining text from the string, you need to add the following as a variable in your scanf
%[ -~]
Example:
sscanf($sql, "[%d,%d]%[ -~]", $sheet_id, $column, $remaining_sql);
Here is an example how alignment, padding and precision specifier can be used to print formatted list of items:
<?php
$out = "The Books\n";
$books = array("Book 1", "Book 2", "Book 3");
$pages = array("123 pages ", "234 pages", "345 pages");
for ($i = 0; $i < count($books); $i++) {
$out .= sprintf("%'.-20s%'.7.4s\n", $books[$i], $pages[$i]);
}
echo $out;
// Outputs:
//
// The Books
// Book 1.................123
// Book 2.................234
// Book 3.................345
?>
Be careful if you use the %f modifier to round decimal numbers as it (starting from 4.3.10) will no longer produce a float number if you set certain locales, so you can't accumulate the result. For example:
setlocale(LC_ALL, 'es_ES');
echo(sprintf("%.2f", 13.332) + sprintf("%.2f", 14.446))
gives 27 instead of 27.78, so use %F instead.
In the examples, is being shown printf, but it should say sprintf, which is the function being explained... just a simple edition mistake.
php printf and sprintf not seems to support star "*" formatting.
here is an example:
printf("%*d\n",3,5);
this will print just "d" instead of "<two spaces>5"
In the last example of Example#6, there is an error regarding the output.
printf("[%10.10s]\n", $t); // left-justification but with a cutoff of 10 characters
This outputs right-justified.
In order to output left-justified:
printf("[%-10.10s]\n", $t);
To add to other notes below about floating point problems, I noted that %f and %F will apparently output a maximum precision of 6 as a default so you have to specify 1.15f (eg) if you need more.
In my case, the input (from MySQL) was a string with 15 digits of precision that was displayed with 6. Likely what happens is that the rounding occurs in the conversion to a float before it is displayed. Displaying it as 1.15f (or in my case, %s) shows the correct number.
If the format string is enclosed in double-quotes (""), you need to escape the dollar sign after argnum with a backslash character (\), like this %1\$s, so that the PHP doesn't try to interpret them as variable. Using a backslash like this is called an escape sequence.
<?php
// Sample string
$number = 499;
$format = "The number without decimal points: %1\$d, and the number with two decimal points: %1\$.2f";
// Formatting and print the string
printf($format, $number);
?>
An error in my last example:
$b = sprintf("%30.s", $a);
will only add enough spaces before $a to pad the spaces + strlen($a) to 30 places.
My method of centering fixed text in a 72 character width space is:
$a = "Some string here";
$lwidth = 36; // 72/2
$b = sprintf("%".($lwidth + round(strlen($a)/2)).".s", $a);
There is a minor issue in a code of mb_vsprintf function from viktor at textalk dot com.
In "truncate $arg" section the following line:
$arg = mb_substr($precision,0,$precision,$encoding);
needs to be replaced with:
$arg = mb_substr($arg,0,$precision,$encoding);
When you're using Google translator, you have to 'escape' the 'conversion specifications' by putting <span class="notranslate"></span> around them.
Like this:
<?php
function getGoogleTranslation($sString, $bEscapeParams = true)
{
// "escape" sprintf paramerters
if ($bEscapeParams)
{
$sPatern = '/(?:%%|%(?:[0-9]+\$)?[+-]?(?:[ 0]|\'.)?-?[0-9]*(?:\.[0-9]+)?[bcdeufFosxX])/';
$sEscapeString = '<span class="notranslate">$0</span>';
$sString = preg_replace($sPatern, $sEscapeString, $sString);
}
// Compose data array (English to Dutch)
$aData = array(
'v' => '1.0',
'q' => $sString,
'langpair' => 'en|nl',
);
// Initialize connection
$rService = curl_init();
// Connection settings
curl_setopt($rService, CURLOPT_URL, 'http://ajax.googleapis.com/ajax/services/language/translate');
curl_setopt($rService, CURLOPT_RETURNTRANSFER, true);
curl_setopt($rService, CURLOPT_POSTFIELDS, $aData);
// Execute request
$sResponse = curl_exec($rService);
// Close connection
curl_close($rService);
// Extract text from JSON response
$oResponse = json_decode($sResponse);
if (isset($oResponse->responseData->translatedText))
{
$sTranslation = $oResponse->responseData->translatedText;
}
else
{
// If some error occured, use the original string
$sTranslation = $sString;
}
// Replace "notranslate" tags
if ($bEscapeParams)
{
$sEscapePatern = '/<span class="notranslate">([^<]*)<\/span>/';
$sTranslation = preg_replace($sEscapePatern, '$1', $sTranslation);
}
// Return result
return $sTranslation;
}
?>
Thanks to MelTraX for defining the RegExp!
Fix for sprintfn function for named arguments (http://php.net/manual/en/function.sprintf.php#94608):
Change the first line from:
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
to:
$arg_nums = array_keys($args);
array_unshift($arg_nums, 0);
$arg_nums = array_flip(array_slice($arg_nums, 1, NULL, true));
I've performed a simple speed test. sprintf against PHP string concatenation operator. Test was performed on PHP 7.3 for 1 million interations.
I run this several times and what I've noted that string concatenation took about 2.9 seconds, sprintf took 4.3 seconds.
I was thinking about what is faster, what is better to do when we're going to format our string (for example, the message to the user or for log purposes) containing some variables values. Is it better to concatenate string with variables using operator (dot ".") or to use sprintf. The answer is: when you do not plan to implement any multilanguage mechanisms and feel good with hardcoding some texts, the "dot" is almost 1.5 times faster!
Here's the code:
echo 'Start' . PHP_EOL;
$vS_text = 'some text';
$vS = '';
$vf = microtime(true);
for ($vI = 0; $vI < 1000000; $vI++) {
$vS = 'Start ' . $vI . ' ' . $vS_text . ' ' . $vf . ' end';
}
$vf = microtime(true) - $vf;
echo 'Concat:' . $vf . PHP_EOL;
$vS = '';
$vf = microtime(true);
for ($vI = 0; $vI < 1000000; $vI++) {
$vS = sprintf('Start %d %s %f end', $vI, $vS_text, $vf);
}
$vf = microtime(true) - $vf;
echo 'Spritf:' . $vf . PHP_EOL;
echo sprintf("%.2f", "123456789012345.82");
// result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.85");
// result: 123456789012345.84
echo sprintf("%.2f", "123456789012345.87");
//result: 123456789012345.88
echo sprintf("%.2f", "123456789012345.820");
//result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.821");
//result: 123456789012345.83
echo sprintf("%.2f", "123456789012345.828");
//result: 123456789012345.83
echo sprintf("%.2f", "123456789012345.8209");
//result : 123456789012345.83
echo sprintf("%.2f", "1234567890123456.82");
//result: 1234567890123456.75
echo sprintf("%.2f", "123456789012345.82002");
//result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.820001");
//result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.820101");
//result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.820201");
//result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.820301");
//result: 123456789012345.81
echo sprintf("%.2f", "123456789012345.820401");
//result: 123456789012345.83