使用 printf() 和 sprintf() 函数时,转义字符不是反斜杠 '\',而是 '%'.
例如,要打印 '%' 字符,需要用它本身转义
<?php
printf('%%%s%%', 'koko'); #output: '%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
类型说明符忽略填充和宽度。
尝试将字符串和宽度说明符组合使用,以及需要多个字节来表示一个字符的字符集,可能会导致意外的结果。
变量将被强制转换为适合说明符的类型
类型 | 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'); #output: '%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 获取更详细的解释。
尝试使用重复占位符重构较长的字符串时要小心,例如
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('%name$s', array('name' => 'Joe')); 代替 sprintf('%1$s', '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));
}
?>
我在尝试找到一个 32 位数字的二进制补码时做了一个噩梦。
我从 http://www.webmasterworld.com/forum88/13334.htm(应归功于其)获得此信息。
引用:...找出任何数字的 2 补码,即 -(pow(2, n) - N),其中 n 是位数,N 是要查找其 2 补码的数字。
这对我有奇效...之前我尝试使用
sprintf ("%b",$32BitDecimal);
但当 $32BitDecimal 值超过 2,000,000,000 时,它总是返回 10000000000000000000000。
这个 -(pow(2, n) - N)
效果非常好,而且非常准确。
希望这能帮助一些在 PHP 中与 2 补码作斗争的人。
为了详细说明 downright 关于 %f 不同含义的观点,它似乎从 4.3.7 版本开始发生了重大变化,而不仅仅是在不同平台上有所不同。以前,宽度说明符指定的是小数点前的字符数量。现在,宽度说明符指定的是总字符数量。(这与其他语言中 printf() 的语义一致。)请查看错误 #28633 和 #29286 以了解更多详细信息。
如果你使用默认的填充说明符(空格),然后将其打印到 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)));
}
?>
继续讨论基于键的 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));
?>
干杯!
将 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() 中使用 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 缓存,然后你就完成了。
如果你想将十进制(整数)数字转换为固定长度的二进制数字,例如 9 位,请使用以下方法
$binary = sprintf('%08b', $number );
例如
<?php
$bin = sprintf('%08b',511 );
echo $bin."\n";
?>
将输出 111111111
而 2 将输出 00000010
我知道这些前导零对我来说很有用,也许对其他人也很有用。
那个帮助我很多的老“猴子”例子不幸消失了。
我将把它作为回忆在评论中重新发布。
<?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]
*/
?>
提醒初学者:示例 6 'printf("[%10s]\n", $s);' 只有在使用 html '<pre></pre>' 标签时才起作用(即显示空格)(节省头部刮取时间;-)。
我在上面的文档中找不到应该是一个警告的信息,那就是如果你的格式化字符串中的格式说明符比要匹配的变量多,sprintf 将什么都不返回。我认为,这一点也应该在返回值部分说明。
请注意,在使用参数交换时,你必须对每个参数进行编号,否则 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
?>
对于 jrust at rustyparts.com,请注意,如果使用双引号字符串并且 *不* 使用反斜杠转义美元符号,则 $s 和 $d 将被解释为变量引用。反斜杠本身不属于格式说明符,但在编写格式字符串时需要包含它(除非使用单引号)。
如果使用参数编号,则具有相同编号的格式规范将获得相同的参数;这可以节省在函数调用中重复参数。
<?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 = "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;
// 输出:
//
// The Books
// Book 1.................123
// Book 2.................234
// Book 3.................345
?>
在 Example#6 的最后一个示例中,关于输出存在错误。
printf("[%10.10s]\n", $t); // 左对齐,但截断为 10 个字符
这将输出右对齐。
为了输出左对齐
printf("[%-10.10s]\n", $t);
如果格式字符串用双引号("")括起来,则需要在 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);
?>
php printf 和 sprintf 似乎不支持星号“*”格式。
以下是一个示例
printf("%*d\n",3,5);
这将打印“d”而不是“<两个空格>5”
为了补充下面关于浮点数问题的其他说明,我注意到 %f 和 %F 显然将输出最大精度为 6 作为默认值,因此如果您需要更多精度,则必须指定 1.15f(例如)。
在我的情况下,输入(来自 MySQL)是一个具有 15 位精度的字符串,显示为 6 位。可能发生的情况是在转换为浮点数之前,在显示之前发生了舍入。将其显示为 1.15f(或在我的情况下为 %s)将显示正确的数字。
我最后一个示例中的错误
$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));
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);
我进行了一个简单的速度测试。将 sprintf 与 PHP 字符串连接运算符进行对比。测试在 PHP 7.3 上进行,共进行 100 万次迭代。
我运行了多次,发现字符串连接大约需要 2.9 秒,而 sprintf 则需要 4.3 秒。
我一直在思考哪种方法更快,当我们要格式化字符串(例如,向用户发送的消息或用于日志记录目的)时,包含一些变量值,哪种方法更好?是使用运算符(点“.”)连接字符串和变量,还是使用 sprintf?答案是:如果你不打算实现任何多语言机制,并且对硬编码一些文本感到满意,那么“点”运算符的速度几乎快 1.5 倍!
以下是代码
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");
// 结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.85");
// 结果:123456789012345.84
echo sprintf("%.2f", "123456789012345.87");
//结果:123456789012345.88
echo sprintf("%.2f", "123456789012345.820");
//结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.821");
//结果:123456789012345.83
echo sprintf("%.2f", "123456789012345.828");
//结果:123456789012345.83
echo sprintf("%.2f", "123456789012345.8209");
//结果:123456789012345.83
echo sprintf("%.2f", "1234567890123456.82");
//结果:1234567890123456.75
echo sprintf("%.2f", "123456789012345.82002");
//结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.820001");
//结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.820101");
//结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.820201");
//结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.820301");
//结果:123456789012345.81
echo sprintf("%.2f", "123456789012345.820401");
//结果:123456789012345.83