vsprintf
(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)
vsprintf — 返回格式化字符串
参数
-
format
-
The format string is composed of zero or more directives: ordinary characters (excluding
%
) that are copied directly to the result and conversion specifications, each of which results in fetching its own parameter.A conversion specification follows this prototype:
%[argnum$][flags][width][.precision]specifier
.Argnum
An integer followed by a dollar sign
$
, to specify which number argument to treat in the conversion.Flags Flag 说明 -
Left-justify within the given field width; Right justification is the default +
Prefix positive numbers with a plus sign +
; Default only negative are prefixed with a negative sign.Pads the result with spaces. This is the default. 0
Only left-pads numbers with zeros. With s
specifiers this can also right-pad with zeros.'
(char)Pads the result with the character (char). Width
An integer that says how many characters (minimum) this conversion should result in.
Precision
A period
.
followed by an integer who's meaning depends on the specifier:-
For
e
,E
,f
andF
specifiers: this is the number of digits to be printed after the decimal point (by default, this is 6). -
For
g
,G
,h
andH
specifiers: this is the maximum number of significant digits to be printed. -
For
s
specifier: it acts as a cutoff point, setting a maximum character limit to the string.
注意: If the period is specified without an explicit value for precision, 0 is assumed.
注意: Attempting to use a position specifier greater than
PHP_INT_MAX
will generate warnings.Specifiers Specifier 说明 %
A literal percent character. No argument is required. b
The argument is treated as an integer and presented as a binary number. c
The argument is treated as an integer and presented as the character with that ASCII. d
The argument is treated as an integer and presented as a (signed) decimal number. e
The argument is treated as scientific notation (e.g. 1.2e+2). E
Like the e
specifier but uses uppercase letter (e.g. 1.2E+2).f
The argument is treated as a float and presented as a floating-point number (locale aware). F
The argument is treated as a float and presented as a floating-point number (non-locale aware). g
General format.
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
The argument is treated as an integer and presented as an octal number. s
The argument is treated and presented as a string. u
The argument is treated as an integer and presented as an unsigned decimal number. x
The argument is treated as an integer and presented as a hexadecimal number (with lowercase letters). X
The argument is treated as an integer and presented as a hexadecimal number (with uppercase letters). 警告The
c
type specifier ignores padding and width警告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
Variables will be co-erced to a suitable type for the specifier:
Type Handling Type Specifiers string s
int d
,u
,c
,o
,x
,X
,b
float e
,E
,f
,F
,g
,G
,h
,H
-
For
-
values
-
返回值
根据 format
和数组参数返回处理后的字符串。
更新日志
版本 | 说明 |
---|---|
8.0.0 |
此函数失败时不再返回 false 。
|
范例
示例 #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() - 格式化一个本地时间/日期

User Contributed Notes 16 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.
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"
?>
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.
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>';
}
}
?>
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.
<?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.
*/
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 );
i wrote a short function that make use of vsprintf. It is useful in first coding/debugging of php scripts, because it is called like a simple printf and it display in italic (you can change it of course ;-) ) every debug messages, making it easy to remove them when your code is ready.
here goes :
<?php
function printd() {
$debug_array=func_get_args();
$debug_numargs=func_num_args();
$debug_fmt=$debug_array[0];
for ( $i = 0 ; $i < $debug_numargs ; $i++ )
$debug_array[$i] = $debug_array[$i+1];
$debug_text=vsprintf($debug_fmt, $debug_array);
printf("--> debug <i>%s</i>\n",
$debug_text);
}
?>
Here's a simple variation on vsprintf() suitable for use with database queries where the results were retrieved as an associative array keyed by column names.
<?php
function dbsprintf($format, $fields, $row)
// $format - sprintf() compatible format string
// $row - Array containing key/value pairs of data
// $fields - Array containing key names (from $row) that are to be used as arguments
{
// Loop through $fields and insert the corresponding values from $row
foreach($fields as &$value)
{
$value = $row[$value];
} unset($value);
// Format the string and return
return vsprintf($format, $fields);
}
// Some data
$row = Array('id' => '12', 'name' => 'World');
// Outputs "Hello World!"
echo dbsprintf('Hello, %s!', Array('name'), $row);
// Outputs "Hello 12!"
echo dbsprintf('Hello, %s!', Array('id'), $row);
?>
Simple but useful routine:
<?php
function vsprintf_iter($fmt,$data) {
if (!is_array($data)) return false;
$ret = '';
foreach ($data as $d) {
$ret .= vsprintf($fmt,$d);
}
return $ret;
}
?>
Heres a new version of the vnsprintf function, i call it dsprintf, but that should matter.
<?php
function dsprintf() {
$data = func_get_args(); // get all the arguments
$string = array_shift($data); // the string is the first one
if (is_array(func_get_arg(1))) { // if the second one is an array, use that
$data = func_get_arg(1);
}
$used_keys = array();
// get the matches, and feed them to our function
$string = preg_replace('/\%\((.*?)\)(.)/e',
'dsprintfMatch(\'$1\',\'$2\',\$data,$used_keys)',$string);
$data = array_diff_key($data,$used_keys); // diff the data with the used_keys
return vsprintf($string,$data); // yeah!
}
function dsprintfMatch($m1,$m2,&$data,&$used_keys) {
if (isset($data[$m1])) { // if the key is there
$str = $data[$m1];
$used_keys[$m1] = $m1; // dont unset it, it can be used multiple times
return sprintf("%".$m2,$str); // sprintf the string, so %s, or %d works like it should
} else {
return "%".$m2; // else, return a regular %s, or %d or whatever is used
}
}
$str = "Hello, %(place)s, how is it hanning at %(place)s? %s works just as well";
$find = array(
'place' => 'world',
'sprintf',
'not used'
);
echo dsprintf($str, $find);
// 'Hello, world, how is it hanning at world? sprintf works just as well'
?>
I found this function to be useful for formatting sql queries.
I do something like this:
function sql_build($template, $params = array()) {
global $sql_templates;
if (isset($sql_templates[$template])) {
$sql = vsprintf($sql_templates[$template], $params);
return $sql;
}
return false;
}
// Fetch list of contacts, for a given section id
$sql_templates['contacts_by_section'] = <<<ENDSQL
select
id,
name,
email,
address,
photo_id
from
contacts
where
section_id = %d
ENDSQL;
You also give yourself an added layer of security on the sql due to the sprintf formatting. For example, using %d will not allow any sql injection for that parameter.
Here is my example for named placeholders. It uses python like named placeholders except that it only allows /[a-z][a-zA-Z0-9_]/ for names.
<?php
/**
* Returns a formatted string. Accepts named arguments.
* @param string $format
* @param array $args
* @return string
**/
function vsprintfn($format, $args) {
// search format patterns
preg_match_all('/((?:^|[^%])(?:%%)*)%(\([a-z][a-zA-Z0-9_]*\))?((\+|-)?(0| |\'.)?-?[0-9\.]*[bcdeEufFgGosxX])/', $format, $matches);
// determine the order of the arguments
$j = 0;
$order = array();
foreach ($matches[0] as $i => $match) {
if ($matches[2][$i] == '') {
$key = $j++;
} else {
$key = substr($matches[2][$i],1,-1);
}
$order[] = $key;
}
// prepare the data array for vsprintf in the given order
$data = array();
foreach ($order as $key) {
if (isset($args[$key])) {
$data[] = $args[$key];
}
}
// replace named format patterns with default format patterns
$format = preg_replace('/((?:^|[^%])(?:%%)*)%(\([a-z][a-zA-Z0-9_]*\))((\+|-)?(0| |\'.)?-?[0-9\.]*[bcdeEufFgGosxX])/', '$1%$3', $format);
// return formatted string
return vsprintf($format, $data);
}
$exampleData = array(0=>2.2314123123,'test'=>2.1234883);
echo vsprintfn('%%2.5f = %2.5f', $exampleData) . "\n";
echo vsprintfn('%%(test)09.5f = %(test)\'%9.5f', $exampleData) . "\n";
?>