使用 printf() 和 sprintf() 函数时,转义字符不是反斜杠 '\' 而是 '%'。
即要打印 '%' 字符,需要用自身转义它
<?php
printf('%%%s%%', 'koko'); #输出: '%koko%'
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
sprintf — 返回格式化的字符串
format
格式字符串由零个或多个指令组成:直接复制到结果中的普通字符(不包括 %
)和转换说明,每个转换说明都会获取自己的参数。
转换说明遵循以下原型:%[argnum$][flags][width][.precision]specifier
。
后跟美元符号 $
的整数,用于指定转换时要处理的哪个编号参数。
Flag | 描述 |
---|---|
- |
在给定的字段宽度内左对齐;右对齐为默认值 |
+ |
在正数前加正号 + ;默认情况下,只有负数前加负号。 |
(空格) |
用空格填充结果。这是默认值。 |
0 |
仅用零填充数字的左侧。对于 s 说明符,这也可以用零填充右侧。 |
' (字符) |
用字符 (char) 填充结果。 |
一个整数,表示此转换应产生的字符数(最小值),或 *
。如果使用 *
,则宽度作为附加整数提供,该整数位于由说明符格式化的整数之前。
一个句点 .
,后跟一个整数或 *
(可选),其含义取决于说明符
e
、E
、f
和 F
说明符:这是小数点后要打印的位数(默认情况下,为 6)。
g
、G
、h
和 H
说明符:这是要打印的最大有效数字位数。
s
说明符:它充当截止点,为字符串设置最大字符限制。
注意: 如果指定了句点但没有为精度提供显式值,则假定为 0。如果使用
*
,则精度作为附加整数提供,该整数位于由说明符格式化的整数之前。
Specifier | 描述 |
---|---|
% |
一个文字百分号字符。不需要参数。 |
b |
参数被视为整数,并作为二进制数显示。 |
c |
参数被视为整数,并作为具有该 ASCII 值的字符显示。 |
d |
参数被视为整数,并作为(带符号的)十进制数显示。 |
e |
参数被视为科学记数法(例如 1.2e+2)。 |
E |
类似于 e 说明符,但使用大写字母(例如 1.2E+2)。 |
f |
参数被视为浮点数,并作为浮点数显示(区域设置感知)。 |
F |
参数被视为浮点数,并作为浮点数显示(非区域设置感知)。 |
g |
通用格式。 令 P 等于精度(如果非零),如果省略精度则为 6,如果精度为零则为 1。然后,如果使用 E 样式的转换具有 X 的指数 如果 P > X ≥ −4,则转换使用 f 样式和精度 P − (X + 1)。否则,转换使用 e 样式和精度 P − 1。 |
G |
类似于 g 说明符,但使用 E 和 f 。 |
h |
类似于 g 说明符,但使用 F 。从 PHP 8.0.0 开始可用。 |
H |
类似于 g 说明符,但使用 E 和 F 。从 PHP 8.0.0 开始可用。 |
o |
参数被视为整数,并作为八进制数显示。 |
s |
参数被视为字符串并显示为字符串。 |
u |
参数被视为整数,并作为无符号十进制数显示。 |
x |
参数被视为整数,并作为十六进制数显示(使用小写字母)。 |
X |
参数被视为整数,并作为十六进制数显示(使用大写字母)。 |
c
类型说明符忽略填充和宽度。
尝试将字符串和宽度说明符组合与每个字符需要多个字节的字符集一起使用可能会导致意外结果。
变量将强制转换为适合说明符的类型
Type | Specifiers |
---|---|
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 开始,当提供的参数少于需要时,会抛出 ArgumentCountError。在 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 | 当提供的参数少于所需参数时,抛出 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
使用 printf() 和 sprintf() 函数时,转义字符不是反斜杠 '\' 而是 '%'。
即要打印 '%' 字符,需要用自身转义它
<?php
printf('%%%s%%', 'koko'); #输出: '%koko%'
?>
1. 加号 ('+') 表示在正数前放置 '+',而减号 ('-') 表示左对齐。文档错误地说明它们是可互换的。它们产生独特的结果,可以组合使用
<?php
echo sprintf ("|%+4d|%+4d|\n", 1, -1);
echo sprintf ("|%-4d|%-4d|\n", 1, -1);
echo sprintf ("|%+-4d|%+-4d|\n", 1, -1);
?>
输出
| +1| -1|
|1 |-1 |
|+1 |-1 |
2. 使用 '0' 填充不同于使用其他字符填充。零只会添加到数字的前面,符号之后。其他字符将添加到符号之前或数字之后
<?php
echo sprintf ("|%04d|\n", -2);
echo sprintf ("|%':4d|\n", -2);
echo sprintf ("|%-':4d|\n", -2);
// 指定 "-" 和 "0" 会导致冲突,产生意外的结果:
echo sprintf ("|%-04d|\n", -2);
// 使用其他数字填充的行为类似于其他非零字符:
echo sprintf ("|%-'14d|\n", -2);
echo sprintf ("|%-'04d|\n", -2);
?>
输出
|-002|
|::-2|
|-2::|
|-2 |
|-211|
|-2 |
以下是如何打印浮点数,无论其大小如何,都具有 16 位有效数字
<?php
$result = sprintf(sprintf('%%.%dF', max(15 - floor(log10($value)), 0)), $value);
?>
这比执行类似 sprintf('%.15F', $value) 的操作更可靠,因为后者可能会截断非常小的数字的有效数字,或者对于非常大的数字打印虚假数字(意味着超出浮点数可以可靠表示的范围的额外数字)。
已经有一些关于使用 sprintf 强制前导零的评论,但示例仅包含整数。我需要浮点数的前导零,并且惊讶地发现它没有按预期工作。
示例
<?php
sprintf('%02d', 1);
?>
这将导致 01。但是,尝试对具有精度的浮点数执行相同的操作不起作用
<?php
sprintf('%02.2f', 1);
?>
输出结果为 1.00。
这让我有点困惑。为了得到想要的结果,需要将精度 (2) 和小数点分隔符 "." 的长度 (1) 加起来。所以正确的格式应该是
<?php
sprintf('%05.2f', 1);
?>
输出:01.00
请参阅 http://stackoverflow.com/a/28739819/413531 获取更详细的解释。
如果格式字符串用双引号 ("") 括起来,则需要使用反斜杠字符 (\) 对 argnum 后面的美元符号进行转义,例如 %1\$s,以防止 PHP 将其解释为变量。使用反斜杠这种方式称为转义序列。
<?php
// 示例字符串
$number = 499;
$format = "The number without decimal points: %1\$d, and the number with two decimal points: %1\$.2f";
// 格式化并打印字符串
printf($format, $number);
?>
在尝试重构包含重复占位符的较长字符串时要小心,例如
sprintf("Hi %s. Your name is %s", $name, $name);
使用参数编号
sprintf("Hi %1$s. Your name is %1$s", $name);
这会导致在**运行时**出现错误,因为 `$s` 被处理为变量。如果没有 `$s` 用于替换,则会抛出通知。
解决方法是使用单引号来防止字符串中的变量替换
sprintf('Hi %1$s. Your name is %1$s', $name);
如果需要变量替换,则需要拆分字符串以将其保留在单引号中
sprintf("Hi " . '%1$s' . ". Your {$variable} is " . '%1$s', $name);
一个更完整且可工作的 mb_sprintf 和 mb_vsprintf 版本。它应该适用于任何“ASCII 保留”编码,例如 UTF-8 和所有 ISO-8859 字符集。它处理符号、填充、对齐、宽度和精度。未处理参数交换。
<?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')) {
/**
* 支持所有编码的格式和参数。
* 支持:符号、填充、对齐、宽度和精度。
* 不支持:参数交换。
*/
function mb_vsprintf($format, $argv, $encoding=null) {
if (is_null($encoding))
$encoding = mb_internal_encoding();
// 在格式中使用 UTF-8,以便我们可以在 preg_split 中使用 u 标志
$format = mb_convert_encoding($format, 'UTF-8', $encoding);
$newformat = ""; // 使用 UTF-8 构建新的格式
$newargv = array(); // 未处理的参数使用未更改的编码
while ($format !== "") {
// 将格式拆分为两个部分:$pre 和 $post,以第一个 %-指令为分隔符
// 我们也获得了匹配的组
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 == '') {
// 没有匹配。什么也不做。这是最后一次迭代。
}
elseif ($type == '%') {
// 转义的 %
$newformat .= '%%';
}
elseif ($type == 's') {
$arg = array_shift($argv);
$arg = mb_convert_encoding($arg, 'UTF-8', $encoding);
$padding_pre = '';
$padding_post = '';
// 截断 $arg
if ($precision !== '') {
$precision = intval(substr($precision,1));
if ($precision > 0 && mb_strlen($arg,$encoding) > $precision)
$arg = mb_substr($precision,0,$precision,$encoding);
}
// 定义填充
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);
}
}
// 转义 % 并传递
$newformat .= $padding_pre . str_replace('%', '%%', $arg) . $padding_post;
}
else {
// 其他类型,传递
$newformat .= "%$sign$filler$align$size$precision$type";
$newargv[] = array_shift($argv);
}
$format = strval($post);
}
// 将新格式从 UTF-8 转换回原始编码
$newformat = mb_convert_encoding($newformat, $encoding, 'UTF-8');
return vsprintf($newformat, $newargv);
}
}
?>
这是一个干净且可工作的函数版本,允许使用命名参数而不是数字参数。例如:与其使用 sprintf('%1$s', 'Joe');,我们可以使用 sprintf('%name$s', array('name' => 'Joe'));。我提供了两个不同的版本:第一个使用类似 PHP 的语法(例如:%name$s),而第二个使用 Python 语法(例如:%(name)s)。
<?php
/**
* 当需要命名参数时,sprintf 的版本(PHP 语法)
*
* 使用 sprintf:sprintf('second: %2$s ; first: %1$s', '1st', '2nd');
*
* 使用 sprintfn:sprintfn('second: %second$s ; first: %first$s', array(
* 'first' => '1st',
* 'second'=> '2nd'
* ));
*
* @param string $format sprintf 格式字符串,包含任意数量的命名参数
* @param array $args 数组,[ 'arg_name' => 'arg value', ... ] 需要替换的内容
* @return string|false sprintf 调用的结果,或错误时的布尔值 false
*/
function sprintfn ($format, array $args = array()) {
// 命名参数与其对应的 sprintf 数字参数值的映射
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
// 查找下一个命名参数。每次搜索都从上一次替换的末尾开始。
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];
// 程序员没有为格式字符串中找到的命名参数提供值
if (! array_key_exists($arg_key, $arg_nums)) {
user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
return false;
}
// 将命名参数替换为相应的数字参数
$format = substr_replace($format, $replace = $arg_nums[$arg_key], $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace); // 跳到替换的末尾,用于下一次迭代
}
return vsprintf($format, array_values($args));
}
/**
* 当需要命名参数时,sprintf 的版本(Python 语法)
*
* 使用 sprintf:sprintf('second: %2$s ; first: %1$s', '1st', '2nd');
*
* 使用 sprintfn:sprintfn('second: %(second)s ; first: %(first)s', array(
* 'first' => '1st',
* 'second'=> '2nd'
* ));
*
* @param string $format sprintf 格式字符串,包含任意数量的命名参数
* @param array $args 数组,[ 'arg_name' => 'arg value', ... ] 需要替换的内容
* @return string|false sprintf 调用的结果,或错误时的布尔值 false
*/
function sprintfn ($format, array $args = array()) {
// 命名参数与其对应的 sprintf 数字参数值的映射
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
// 查找下一个命名参数。每次搜索都从上一次替换的末尾开始。
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];
// 程序员没有为格式字符串中找到的命名参数提供值
if (! array_key_exists($arg_key, $arg_nums)) {
user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
return false;
}
// 将命名参数替换为相应的数字参数
$format = substr_replace($format, $replace = $arg_nums[$arg_key] . '$', $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace); // 跳到替换的末尾,用于下一次迭代
}
return vsprintf($format, array_values($args));
}
?>
为了详细说明 downright 关于 %f 不同含义的观点,似乎从 4.3.7 版本开始,行为发生了重大变化,而不仅仅是在不同平台上有所不同。以前,宽度说明符给出小数点**之前**允许的字符数。现在,宽度说明符给出字符的**总数**。(这与其他语言中 printf() 的语义一致。)有关更多详细信息,请参阅错误 #28633 和 #29286。
我做了一个噩梦,试图找到一个 32 位数的二进制补码。
我从 http://www.webmasterworld.com/forum88/13334.htm 获取了这个信息(应归功于……=P)。
引用:“……找到任何数字的二进制补码,即 -(pow(2, n) - N),其中 n 是位数,N 是要查找其二进制补码的数字。”
这对我有奇效……之前我尝试使用
sprintf ("%b",$32BitDecimal);
但当 $32BitDecimal 值超过 2,000,000,000 时,它总是返回 10000000000000000000000。
这个 -(pow(2, n) - N)
效果非常好,非常准确。
希望这对在 PHP 中处理二进制补码的人有所帮助。
如果使用默认的填充说明符(空格),然后将其打印到 HTML,您会注意到 HTML 无法正确显示多个空格。这是因为任何空格序列都被视为单个空格。
为了克服这个问题,我编写了一个简单的函数,将 sprintf() 返回的字符串中的所有空格替换为字符实体引用“ ”,从而在 sprintf() 返回的字符串中实现不换行空格。
<?php
//这是函数:
function sprintf_nbsp() {
$args = func_get_args();
return str_replace(' ', ' ', vsprintf(array_shift($args), array_values($args)));
}
//用法(完全像 sprintf):
$format = 'The %d monkeys are attacking the [%10s]!';
$str = sprintf_nbsp($format, 15, 'zoo');
echo $str;
?>
以上示例将输出
The 15 monkeys are attacking the [ zoo]!
<?php
//打印字符串而不是返回字符串的变体:
function printf_nbsp() {
$args = func_get_args();
echo str_replace(' ', ' ', vsprintf(array_shift($args), array_values($args)));
}
?>
将IP地址编码和解码为格式:1A2B3C4D(mysql列: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]);
}
?>
并且继续讨论基于键的 sprintf 的相同主题...
我大致(我可以看到几个出现奇怪结果的情况)复制了 Python 字符串格式化与字典的语法。与之前几次尝试相比,这次改进在于它仍然尊重所有格式化选项,正如你在我的示例中看到的。
并且错误处理非常糟糕(只是一个 echo)。我只是把它放在一起,所以你可以随意使用它。=]
<?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));
?>
干杯!
如果你想将十进制(整数)数字转换为例如9位的固定长度二进制数字,请使用此方法
$binary = sprintf('%08b', $number );
例如
<?php
$bin = sprintf('%08b',511 );
echo $bin."\n";
?>
将输出111111111
并且2将输出00000010
我知道前导零对我很有用,也许对其他人也有用。
在 sprintf() 中使用参数交换与 gettext:假设你编写了以下脚本
<?php
$var = sprintf(gettext("The %2\$s contains %1\$d monkeys"), 2, "cage");
?>
现在你运行 xgettext 以生成 .po 文件。然后 .po 文件将如下所示
#: file.php:9
#, ycp-format
msgid "The %2\\$s contains %1\\$d monkeys"
msgstr ""
请注意,xgettext 添加了一个额外的反斜杠。
翻译完字符串后,必须从 ID 字符串以及翻译中删除所有反斜杠,因此 po 文件将如下所示
#: file.php:9
#, ycp-format
msgid "The %2$s contains %1$d monkeys"
msgstr "Der er %1$d aber i %2$s"
现在运行 msgfmt 生成 .mo 文件,如果需要,重新启动 Apache 以删除 gettext 缓存,然后你就可以开始了。
对于 jrust at rustyparts.com,请注意,如果你使用双引号字符串并且*不*使用反斜杠转义美元符号,则 $s 和 $d 将被解释为变量引用。反斜杠本身不是格式说明符的一部分,但当你编写格式字符串时确实需要包含它(除非你使用单引号)。
我在上面的文档中找不到应该作为警告的内容,即如果你有比变量更多的说明符来匹配它们,sprintf 将返回**没有任何内容**。在我看来,这一点也应该在返回值下进行说明。
帮助我很多的老“猴子”示例遗憾地消失了。
我将在评论中重新发布它以作纪念。
<?php
$n = 43951789;
$u = -43951789;
$c = 65; // ASCII 65 是 'A'
// 注意双百分号,这会打印一个字面上的 '%' 字符
printf("%%b = '%b'\n", $n); // 二进制表示
printf("%%c = '%c'\n", $c); // 打印 ASCII 字符,与 chr() 函数相同
printf("%%d = '%d'\n", $n); // 标准整数表示
printf("%%e = '%e'\n", $n); // 科学计数法
printf("%%u = '%u'\n", $n); // 正整数的无符号整数表示
printf("%%u = '%u'\n", $u); // 负整数的无符号整数表示
printf("%%f = '%f'\n", $n); // 浮点数表示
printf("%%o = '%o'\n", $n); // 八进制表示
printf("%%s = '%s'\n", $n); // 字符串表示
printf("%%x = '%x'\n", $n); // 十六进制表示(小写)
printf("%%X = '%X'\n", $n); // 十六进制表示(大写)
printf("%%+d = '%+d'\n", $n); // 正整数上的符号说明符
printf("%%+d = '%+d'\n", $u); // 负整数上的符号说明符
/*
%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); // 标准字符串输出
printf("[%10s]\n", $s); // 右对齐,用空格填充
printf("[%-10s]\n", $s); // 左对齐,用空格填充
printf("[%010s]\n", $s); // 零填充也适用于字符串
printf("[%'#10s]\n", $s); // 使用自定义填充字符 '#'
printf("[%10.10s]\n", $t); // 左对齐,但截断为 10 个字符
/*
[monkey]
[ monkey]
[monkey ]
[0000monkey]
[####monkey]
[many monke]
*/
?>
请注意,当使用参数交换时,必须为每个参数编号,否则 sprintf 会感到困惑。只有当您首先使用数字参数,然后切换到非编号参数,然后再切换回编号参数时,才会发生这种情况。
<?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" );
// 无法工作:
// Sprintf 会抱怨参数不足。
$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" );
// 可以工作:请注意 %3\$s
?>
如果使用参数编号,则具有相同编号的格式说明符将获取相同的参数;这可以节省在函数调用中重复参数的麻烦。
<?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');
预期输出
"There are 100 monkeys in the Chennai and bangalore"
但是,这将输出
"There are 100 monkeys in the 100 and Chennai"
因为,第二个和第三个说明符获取第一个和第二个参数。因为它们没有分配任何参数。
如果您使用 %f 修饰符来舍入十进制数字,请小心,因为它(从 4.3.10 开始)在设置某些区域设置时将不再生成浮点数,因此您无法累积结果。例如
setlocale(LC_ALL, 'es_ES');
echo(sprintf("%.2f", 13.332) + sprintf("%.2f", 14.446))
给出 27 而不是 27.78,因此请使用 %F 代替。
当您使用 Google 翻译时,您必须通过在 <span class="notranslate"></span> 周围放置来“转义” “转换说明符”。
像这样
<?php
function getGoogleTranslation($sString, $bEscapeParams = true)
{
// "转义" sprintf 参数
if ($bEscapeParams)
{
$sPatern = '/(?:%%|%(?:[0-9]+\$)?[+-]?(?:[ 0]|\'.)?-?[0-9]*(?:\.[0-9]+)?[bcdeufFosxX])/';
$sEscapeString = '<span class="notranslate">$0</span>';
$sString = preg_replace($sPatern, $sEscapeString, $sString);
}
// 组成数据数组(英语到荷兰语)
$aData = array(
'v' => '1.0',
'q' => $sString,
'langpair' => 'en|nl',
);
// 初始化连接
$rService = curl_init();
// 连接设置
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);
// 执行请求
$sResponse = curl_exec($rService);
// 关闭连接
curl_close($rService);
// 从 JSON 响应中提取文本
$oResponse = json_decode($sResponse);
if (isset($oResponse->responseData->translatedText))
{
$sTranslation = $oResponse->responseData->translatedText;
}
else
{
// 如果发生某些错误,则使用原始字符串
$sTranslation = $sString;
}
// 替换 "notranslate" 标签
if ($bEscapeParams)
{
$sEscapePatern = '/<span class="notranslate">([^<]*)<\/span>/';
$sTranslation = preg_replace($sEscapePatern, '$1', $sTranslation);
}
// 返回结果
return $sTranslation;
}
?>
感谢 MelTraX 定义正则表达式!
以下是如何使用对齐、填充和精度说明符来打印格式化项目列表的示例
<?php
$out = "书籍列表\n";
$books = array("书籍 1", "书籍 2", "书籍 3");
$pages = array("123 页 ", "234 页", "345 页");
for ($i = 0; $i < count($books); $i++) {
$out .= sprintf("%'.-20s%'.7.4s\n", $books[$i], $pages[$i]);
}
echo $out;
// 输出结果:
//
// 书籍列表
// 书籍 1.................123
// 书籍 2.................234
// 书籍 3.................345
?>
补充一下关于浮点数问题的其他说明,我注意到 %f 和 %F 似乎默认输出最多 6 位精度,因此如果您需要更多精度,则必须指定 1.15f(例如)。
在我的例子中,输入(来自 MySQL)是一个具有 15 位精度的字符串,显示为 6 位。可能发生的情况是在转换为浮点数之前,在转换过程中进行了舍入,然后才显示。将其显示为 1.15f(或在我的例子中为 %s)会显示正确的数字。
在示例 #6 的最后一个示例中,输出部分存在错误。
printf("[%10.10s]\n", $t); // 左对齐,但截取 10 个字符
这会输出右对齐的结果。
为了输出左对齐的结果,
printf("[%-10.10s]\n", $t);
我上一个示例中的错误
$b = sprintf("%30.s", $a);
只会添加足够的空格在 $a 前面,使空格 + strlen($a) 达到 30 个字符。
我在 72 个字符宽度的空间中居中固定文本的方法是
$a = "Some string here";
$lwidth = 36; // 72/2
$b = sprintf("%".($lwidth + round(strlen($a)/2)).".s", $a);
针对带命名参数的 sprintfn 函数的修复 (https://php.net/manual/en/function.sprintf.php#94608)
将第一行从
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
改为
$arg_nums = array_keys($args);
array_unshift($arg_nums, 0);
$arg_nums = array_flip(array_slice($arg_nums, 1, NULL, true));
php 的 printf 和 sprintf 似乎不支持星号 "*" 格式。
这是一个例子
printf("%*d\n",3,5);
这将打印 "d" 而不是 "<两个空格>5"
viktor at textalk dot com 编写的 mb_vsprintf 函数代码中存在一个小问题。
在“截断 $arg”部分,以下行
$arg = mb_substr($precision,0,$precision,$encoding);
需要替换为
$arg = mb_substr($arg,0,$precision,$encoding);
只想补充一点,要获取字符串中剩余的文本,您需要在 scanf 中添加以下内容作为变量
%[ -~]
示例
sscanf($sql, "[%d,%d]%[ -~]", $sheet_id, $column, $remaining_sql);