vsprintf

(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)

vsprintf返回格式化字符串

说明

vsprintf ( string $format , array $values ) : string

作用与 sprintf() 函数类似,但是接收一个数组参数,而不是一系列可变数量的参数。

参数

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.
(space) 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 and F specifiers: this is the number of digits to be printed after the decimal point (by default, this is 6).
  • For g, G, h and H 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.

Note: If the period is specified without an explicit value for precision, 0 is assumed.

Note: 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 uses E and f.
h Like the g specifier but uses F. Available as of PHP 8.0.0.
H Like the g specifier but uses E and F. 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).

Warning

The c type specifier ignores padding and width

Warning

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

values

返回值

根据 format 和数组参数返回处理后的字符串。

更新日志

版本 说明
8.0.0 此函数失败时不再返回 false

范例

Example #1 vsprintf(): 前导 0 的整数

<?php
print vsprintf("%04d-%02d-%02d"explode('-''1988-8-1'));
?>

以上例程会输出:

1988-08-01

参见

User Contributed Notes

crash 06-Jul-2021 09:03
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.
steven at nevvix dot com 02-May-2018 04:14
<?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.
*/
ASchmidt at Anamera dot net 21-Nov-2017 06:58
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 );
spectrumcat 28-Sep-2016 10:51
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);
dee jay simple zero07 at geemail dawt co 17-Jan-2013 05:03
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;
?>
Josef Kufner 20-Nov-2012 11:51
<?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);
}
?>
thomas att familie dash flori dot de 30-Oct-2012 11:46
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";

?>
strata_ranger at hotmail dot com 29-Jun-2010 11:15
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);

?>
jeppe dot dyrby at gmail dot com 04-Mar-2009 04:52
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'
?>
www dot wesley at gmail dot com 16-Jun-2008 01:56
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

Note1: 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.
Note2: "%+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"
?>
Roadster 30-Sep-2006 07:44
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.
jon at ardentcreative dot co dot uk 17-Feb-2006 03:56
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>';
    }
}
?>
toneee at g mail dot com 19-Dec-2005 09:27
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.
tbS dot P dot A dot M at S dot U dot K dot Staylorbarstow dot com 01-Mar-2005 11:49
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;
}
?>
jed at NOSPAM dot jed dot bz 22-May-2004 06:48
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.
samviseNOSPAM at hobbitonNOSPAM dot it 02-Jul-2002 06:55
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);
}
?>