vsprintf
(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)
vsprintf — 返回格式化字符串
参数
format
-
format 字符串通常由零或多个指令组成:普通字符(不包含
%
)——直接复制到结果,转换规范——获取每个参数的结果。转换规范遵循此原型:
%[argnum$][flags][width][.precision]specifier
.Argnum
整数后跟美元符号
$
,用于指定转换中要处理的参数数量。标志 标志 说明 -
在指定字段宽度时左对齐,默认右对齐 +
正数的加号 +
前缀,默认负数的前缀是负号。空格填充结果。这是默认设置。 0
仅用 0 进行左侧数字填充。使用 s
标志符可以右侧填充。'
(char)用字符(char)填充结果。 Width
要么是整数,表示转换结果应该有多少个字符(最少),要么是
*
。如果使用*
,那么宽度将作为额外的整数值提供,位于格式化符号之前。Precision
小数点
.
,可选的后跟整数或者*
,其含义取决于格式化符号:-
e
、E
、f
、F
标志符:小数点后需要打印的位数(默认是 6)。 -
g
、G
、h
、H
标志符:这是要打印的最大有效位数。 -
s
标志符:充当分界点,为字符串设置最大字符限制。
注意: 如果小数点没有明确的精度值,则假设是 0。如果使用
*
,则精度将作为额外的整数值提供,位于格式化符号之前。标志符 标志符 说明 %
字面意思的百分号字符。不需要参数。 b
参数视为整数并以二进制数字呈现。 c
参数视为整数并以 ASCII 字符呈现。 d
参数视为整数并以(有符号)十进制数字呈现。 e
参数当做科学符号处理(例如 1.2e+2)。 E
与 e
标志符相同,但使用大写字母(例如 1.2E+2)。f
参数当做浮点数处理且作为浮点数呈现(locale aware)。 F
参数当做浮点数处理且作为浮点数呈现(non-locale aware)。 g
通用格式。
Let P equal the precision if nonzero, 6 if the precision is omitted, or 1 if the precision is zero. Then, if a conversion with style E would have an exponent of X:
If P > X ≥ −4, the conversion is with style f and precision P − (X + 1). Otherwise, the conversion is with style e and precision P − 1.
G
Like the g
specifier but usesE
andf
.h
Like the g
specifier but usesF
. Available as of PHP 8.0.0.H
Like the g
specifier but usesE
andF
. Available as of PHP 8.0.0.o
参数视为整数并以八进制数字来呈现。 s
参数视为字符串来呈现。 u
参数视为整数并以无符号十进制数字呈现。 x
参数视为整数并作为十六进制数字呈现(带小写字母)。 X
参数视为整数并作为十六进制数字呈现(带大写字母)。 警告c
类型标志符忽略填充和宽度。警告Attempting to use a combination of the string and width specifiers with character sets that require more than one byte per character may result in unexpected results.
变量将会强制转换为适合标志符的类型:
类型处理 类型 标志符 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 开始,如果参数个数为零,将抛出 ValueError。在 PHP 8.0.0 之前,会发出 E_WARNING
。
从 PHP 8.0.0 开始,如果 [width]
小于零或大于 PHP_INT_MAX
,则会抛出
ValueError。在 PHP 8.0.0 之前,会发出 E_WARNING
。
从 PHP 8.0.0 开始,如果 [precision]
小于零或大于 PHP_INT_MAX
,则会抛出
ValueError。在 PHP 8.0.0 之前,会发出 E_WARNING
。
从 PHP 8.0.0 开始,当传递的参数少于所需的参数时会抛出 ValueError。在 PHP 8.0.0 之前,返回 false
并发出 E_WARNING
。
更新日志
版本 | 说明 |
---|---|
8.0.0 |
此函数失败时不再返回 false 。
|
8.0.0 |
如果参数个数为零则抛出 ValueError;以前该函数则会发出 E_WARNING 。
|
8.0.0 |
如果 [width] 小于零或大于 PHP_INT_MAX ,则抛出 ValueError;以前该函数则会发出 E_WARNING 。
|
8.0.0 |
如果 [precision] 小于零或大于 PHP_INT_MAX ,则抛出 ValueError;以前该函数则会发出 E_WARNING 。
|
8.0.0 |
当传递的参数少于所需的参数时抛出 ValueError;以前该函数则会发出 E_WARNING 。
|
示例
示例 #1 vsprintf(): 前导 0 的整数
<?php
print vsprintf("%04d-%02d-%02d", explode('-', '1988-8-1'));
?>
以上示例会输出:
1988-08-01
参见
- printf() - 输出格式化字符串
- sprintf() - 返回格式化字符串
- fprintf() - 将格式化后的字符串写入到流
- vprintf() - 输出格式化字符串
- vfprintf() - 将格式化字符串写入流
- sscanf() - 根据指定格式解析输入的字符
- fscanf() - 从文件中格式化输入
- number_format() - 以千位分隔符方式格式化一个数字
- date() - 格式化 Unix 时间戳
用户贡献的备注 10 notes
Instead of inventing own functions in case you'd like to use array keys as placeholder names and replace corresponding array values in a string, just use the str_replace:
$string = 'Hello %name!';
$data = array(
'%name' => 'John'
);
$greeting = str_replace(array_keys($data), array_values($data), $string);
<?php
/**
* Like vsprintf, but accepts $args keys instead of order index.
* Both numeric and strings matching /[a-zA-Z0-9_-]+/ are allowed.
*
* Example: vskprintf('y = %y$d, x = %x$1.1f', array('x' => 1, 'y' => 2))
* Result: 'y = 2, x = 1.0'
*
* $args also can be object, then it's properties are retrieved
* using get_object_vars().
*
* '%s' without argument name works fine too. Everything vsprintf() can do
* is supported.
*
* @author Josef Kufner <jkufner(at)gmail.com>
*/
function vksprintf($str, $args)
{
if (is_object($args)) {
$args = get_object_vars($args);
}
$map = array_flip(array_keys($args));
$new_str = preg_replace_callback('/(^|[^%])%([a-zA-Z0-9_-]+)\$/',
function($m) use ($map) { return $m[1].'%'.($map[$m[2]] + 1).'$'; },
$str);
return vsprintf($new_str, $args);
}
?>
Note that this function now throws an ValueError* as of PHP 8.0 if there is an error:
$ php -r 'var_dump(vsprintf("%d", []));'
> Fatal error: Uncaught ValueError: The arguments array must contain 1 items, 0 given in Command line code:1
*ValueError is new in PHP 8.0, so if you want to make your code compatible to PHP 7.x you should test that the arguments array has the correct length.
<?php
/**
* Return a formatted string like vsprintf() with named placeholders.
*
* When a placeholder doesn't have a matching key in `$args`,
* the placeholder is returned as is to see missing args.
* @param string $format
* @param array $args
* @param string $pattern
* @return string
*/
function p($format, array $args, $pattern="/\{(\w+)\}/") {
return preg_replace_callback($pattern, function ($matches) use ($args) {
return @$args[$matches[1]] ?: $matches[0];
}, $format);
}
$args = ["database"=>"people", "user"=>"staff", "pass"=>"pass123", "host"=>"localhost"];
// With PHP-like placeholders: the variable is embedded in a string "{$database}" but without the dollar sign
$format = <<<SQL
CREATE DATABASE IF NOT EXISTS {database};
GRANT ALL PRIVILEGES ON {database_name}.* TO '{user}'@'{host}';
SET PASSWORD = PASSWORD('{pass}');
SQL;
echo p($format, $args);
/*
Result:
CREATE DATABASE IF NOT EXISTS people;
GRANT ALL PRIVILEGES ON {database_name}.* TO 'staff'@'localhost';
SET PASSWORD = PASSWORD('pass123');
The `{database_name}` placeholder doesn't exist as a matching key in `$args` so it's returned as is.
*/
// With Ruby-like placeholders
$format = <<<SQL
CREATE DATABASE IF NOT EXISTS :database;
GRANT ALL PRIVILEGES ON :database_name.* TO ':user'@':host';
SET PASSWORD = PASSWORD(':pass');
SQL;
echo p($format, $args, "/:(\w+)/");
/*
Result:
CREATE DATABASE IF NOT EXISTS people;
GRANT ALL PRIVILEGES ON :database_name.* TO 'staff'@'localhost';
SET PASSWORD = PASSWORD('pass123');
The `:database_name` placeholder doesn't exist as a matching key in `$args` so it's returned as is.
*/
This can be used for quick and dirty internationalization:
<?php
$GLOBALS['strings']['example'] = "There are %d people.";
// Loads a phrase from the translations list in lang/$lang/phrases.php
function t() {
$args = func_get_args();
$nArgs = func_num_args();
$phrase = array_shift($args);
$nArgs--;
include_once("../lang/" . lang() . "/phrases.php");
if (isset($GLOBALS['strings'][$phrase])) {
return vsprintf($GLOBALS['strings'][$phrase], $args);
} else {
return '<span style="color: #ff0000">Untranslated string: ' . $phrase . '</span>';
}
}
?>
Please note: The same functionality (sortof) can be attained between version 4.0.4 and 4.1.0 using call_user_func_array.
Example:
call_user_func_array("sprintf", $arg)
First element of $arg is the format. This rescued me in a situation where version 4.1.0 wasn't available.
vnsprintf is equal to vsprintf except for associative, signed or floating keys.
vnsprintf supports for example "%assocKey$05d", "%-2$'+10s" and "%3.2$05u", vsprintf doesn't
vnsprintf( '%2$d', $array) [2nd value] is equal to vsprintf( '%2$d', $array) [2nd value]
vnsprintf( '%+2$d', $array) [key = 2] is equal to vnsprintf( '%2.0$d', $array) [key = 2]
vnsprintf( '%+2$d', $array) [key = 2] is different of vsprintf( '%+2$d', $array) [unsupported]
When you use signed or floating keys, vnsprintf searchs for the signed truncated key of the original array
Note¹: vnsprintf does not support for example "%someKeyf" (floating number, key = someKey) or "%+03d" (signed decimal number, key = 3), you should use "%someKey$f" or "%+03$d" respectively.
Note²: "%+03d" (or "%1$+03d") will be interpreted as signed zero-padded decimal number
<?php
function vnsprintf( $format, array $data)
{
preg_match_all( '/ (?<!%) % ( (?: [[:alpha:]_-][[:alnum:]_-]* | ([-+])? [0-9]+ (?(2) (?:\.[0-9]+)? | \.[0-9]+ ) ) ) \$ [-+]? \'? .? -? [0-9]* (\.[0-9]+)? \w/x', $format, $match, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$offset = 0;
$keys = array_keys($data);
foreach ( $match as &$value )
{
if ( ( $key = array_search( $value[1][0], $keys) ) !== FALSE || ( is_numeric( $value[1][0]) && ( $key = array_search( (int)$value[1][0], $keys) ) !== FALSE ) ) {
$len = strlen( $value[1][0]);
$format = substr_replace( $format, 1 + $key, $offset + $value[1][1], $len);
$offset -= $len - strlen( $key);
}
}
return vsprintf( $format, $data);
}
$examples = array(
2.8=>'positiveFloat', // key = 2 , 1st value
-3=>'negativeInteger', // key = -3 , 2nd value
'my_name'=>'someString' // key = my_name , 3rd value
);
echo vsprintf( "%%my_name\$s = '%my_name\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%my_name\$s = '%my_name\$s'\n", $examples); // output : "someString"
echo vsprintf( "%%2.5\$s = '%2.5\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%2.5\$s = '%2.5\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%+2.5\$s = '%+2.5\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%+2.5\$s = '%+2.5\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%-3.2\$s = '%-3.2\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%-3.2\$s = '%-3.2\$s'\n", $examples); // output : "negativeInteger"
echo vsprintf( "%%2\$s = '%2\$s'\n", $examples); // output : "negativeInteger"
echo vnsprintf( "%%2\$s = '%2\$s'\n", $examples); // output : [= vsprintf]
echo vsprintf( "%%+2\$s = '%+2\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%+2\$s = '%+2\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%-3\$s = '%-3\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%-3\$s = '%-3\$s'\n", $examples); // output : "negativeInteger"
?>
Using a heredoc with vprintf:
<?php
$string = <<<THESTRING
I like the state of %1\$s <br />
I picked: %2\$d as a number, <br />
I also picked %2\$d as a number again <br />
%3\$s<br />
THESTRING;
$returnText = vprintf( $string, array('Oregon','7','I Love Oregon') );
echo $returnText;
?>
vsprintf() accepts arrays with any keys, so the array_shift() technique is unnecessary when writing a printf-type function. Any parameters you require are easily unset from the array you retrieve with func_get_args():
<?php
function mysprintf($format) {
$args = func_get_args();
unset($args[0]); /* get rid of "$format" */
return vsprintf($format, $args);
}
/* I use this technique in production code as follows: */
function logf($target, $string) {
$args = func_get_args();
unset($args[0], $args[1]);
fprintf($GLOBALS['config']['logtargets'][$target],
"[%s] %s\n", date('H:i'), wordwrap(vsprintf($string, $args), 75, '\n\r '));
}
/* e.g.:
logf(DEBUG, "Oops! %s", mysql_error());
*/
?>
array_shift() and other costly array operations aren't required, as far as I know. I could be wrong.
It's necessary to clearly how to apply argument swapping when using an array of arguments. One might be tempted to use %0$ to reference $args[0].
In reality, the position specifier is always the array index+1:
$args[0] is referenced by %1$...
$args[1] is referenced by %2$...
etc.
Similarly, the first subpattern of a RegEx match would be found in $matches[1], the second in $match[2], etc. However if the $matches array is used as arguments to vsprint(), then the position specifier is subpattern+1:
preg_match( $pattern, $subject, $matches );
vsprintf( 'Full Match = %1$s, first Subpattern = %2$s, second Subpattern = %3$s', $matches );