我正在尝试更多地了解PHP函数sprintf()但是php.net并没有帮助我,因为我仍然感到困惑,为什么要使用它?
看看下面的例子。
为什么要用这个:
$output = sprintf("Here is the result: %s for this date %s", $result, $date);
如果这样做并且更容易编写IMO:
$output = 'Here is the result: ' .$result. ' for this date ' .$date;
我在这里错过了什么吗?
答案 0 :(得分:124)
sprintf
具有原始printf的所有格式化功能,这意味着您可以做的不仅仅是在字符串中插入变量值。
例如,指定数字格式(十六进制,十进制,八进制),小数位数,填充等。谷歌的printf,你会发现很多例子。 wikipedia article on printf应该让你开始。
答案 1 :(得分:76)
sprintf有很多用例,但我使用它的一种方法是存储一个这样的字符串:'Hello,My Name is%s'在数据库中或作为PHP类中的常量。这样,当我想使用该字符串时,我可以简单地这样做:
$name = 'Josh';
// $stringFromDB = 'Hello, My Name is %s';
$greeting = sprintf($stringFromDB, $name);
// $greetting = 'Hello, My Name is Josh'
基本上它允许在代码中进行一些分离。如果我在我的代码中的许多地方使用'Hello,My Name is%s',我可以在一个地方将其更改为'%s是我的名字',并且它可以自动更新到其他地方,而无需转到每个实例并四处移动级联。
答案 2 :(得分:46)
sprintf
的另一个用途是在本地化的应用程序中,因为sprintf
的参数不必按照它们在格式字符串中出现的顺序。
示例:
$color = 'blue';
$item = 'pen';
sprintf('I have a %s %s', $color, $item);
但像法语这样的语言对单词的命令不同:
$color = 'bleu';
$item = 'stylo';
sprintf('J\'ai un %2$s %1$s', $color, $item);
(是的,我的法语糟透了:我在学校学过德语!)
实际上,您使用gettext来存储本地化字符串,但您明白了。
答案 3 :(得分:36)
翻译更容易。
echo _('Here is the result: ') . $result . _(' for this date ') . $date;
翻译(gettext)字符串现在是:
当翻译成其他语言时,它可能是不可能的,或者导致非常奇怪的句子。
现在,如果你有
echo sprintf(_("Here is the result: %s for this date %s"), $result, $date);
翻译(gettext)字符串现在是:
这更有意义,而且翻译成其他语言更灵活
答案 4 :(得分:16)
我找到的最好的理由是,它允许您将所有语言字符串放在您的语言文件中,如果人们可以翻译并根据需要进行排序 - 但您仍然知道无论字符串是什么格式 - 您希望显示用户名。
例如,您的网站会在页面顶部显示“欢迎回[[用户]]”。作为程序员,您不知道或关心 UI用户将如何编写 - 您只需知道用户名将显示在消息中的某个位置。
因此,您可以将消息嵌入到代码中,而不必担心实际上是什么消息。
Lang文件(EN_US):
...
$lang['welcome_message'] = 'Welcome back %s';
...
然后,您可以在实际的PHP代码中使用它来支持任何语言的任何类型的消息。
sprintf($lang['welcome_message'], $user->name())
答案 5 :(得分:9)
你为什么要使用它?
当使用(外部)源语言字符串时,它非常有用。如果在给定的多语言字符串中需要固定数量的变量,则只需要知道正确的顺序:
<强> en.txt 强>
not_found = "%s could not be found."
bad_argument = "Bad arguments for function %s."
bad_arg_no = "Bad argument %d for function %s."
<强> hu.txt 强>
not_found = "A keresett eljárás (%s) nem található."
bad_argument = "Érvénytelen paraméterek a(z) %s eljárás hívásakor."
bad_arg_no = "Érvénytelen %d. paraméter a(z) %s eljárás hívásakor."
插入的变量甚至不必在多种语言的开头或结尾,只有它们的顺序很重要。
当然,您可以编写自己的函数来执行此替换,毫无疑问,即使性能稍有提高,但更快(假设您有一个类Language
来读取语言字符串):
/**
* throws exception with message($name = "ExampleMethod"):
* - using en.txt: ExampleMethod could not be found.
* - using hu.txt: A keresett eljárás (ExampleMethod) nem található.
*/
throw new Exception(sprintf(Language::Get('not_found'), $name));
/**
* throws exception with message ($param_index = 3, $name = "ExampleMethod"):
* - using en.txt: Bad argument 3 for function ExampleMethod.
* - using hu.txt: Érvénytelen 3. paraméter a(z) ExampleMethod eljárás hívásakor.
*/
throw new Exception(sprintf(Language::Get('bad_arg_no'), $param_index, $name));
它还具有printf
的全部功能,因此也是用于格式化多种类型变量的单行程序,例如:
答案 6 :(得分:8)
如上所述,它允许格式化输入数据。例如,强制使用2dp,4位数字等。这对于构建MySQL查询字符串非常有用。
另一个优点是它允许你将字符串的布局与输入数据的数据分开,就像在参数中输入一样。例如,在MySQL查询的情况下:
// For security, you MUST sanitise ALL user input first, eg:
$username = mysql_real_escape_string($_POST['username']); // etc.
// Now creating the query:
$query = sprintf("INSERT INTO `Users` SET `user`='%s',`password`='%s',`realname`='%s';", $username, $passwd_hash, $realname);
此方法当然有其他用途,例如将输出打印为HTML等时
修改:出于安全原因,使用上述技术时,必须先使用mysql_real_escape_string()
清除所有输入变量,然后再使用此方法,以防止MySQL插入攻击。 如果您解析未经过处理的输入,您的网站和服务器将被黑客入侵。 (当然,除了代码完全构造并保证安全的变量外。)
答案 7 :(得分:6)
使用sprintf()格式化字符串会更清晰,更安全。
例如,当您处理输入变量时,它通过提前指定预期格式(例如,您期望字符串[%s
]或数字[{{1})来防止意外惊喜}])。这可能有助于SQL injection的可能风险,但如果字符串包含引号则不会阻止。
它还有助于处理浮点数,您可以明确指定数字精度(例如%d
),这可以避免使用转换函数。
其他优点是大多数主要的编程语言都有自己的%.2f
实现,所以一旦你熟悉它,它就会更容易使用,而不是学习一门新语言(比如怎么样)连接字符串或转换浮点数。)
总之,使用它是一种很好的做法,以便拥有更清晰,更易读的代码。
例如,请参阅下面的real example:
sprintf()
或者一些简单的例子,例如$insert .= "('".$tr[0]."','".$tr[0]."','".$tr[0]."','".$tr[0]."'),";
:
'1','2','3','4'
并使用格式化字符串打印:
print "foo: '" . $a . "','" . $b . "'; bar: '" . $c . "','" . $d . "'" . "\n";
其中printf("foo: '%d','%d'; bar: '%d','%d'\n", $a, $b, $c, $d);
等同于printf()
,但它输出格式化的字符串而不是将其返回(变量)。
哪个更具可读性?
答案 8 :(得分:4)
即使我有同样的事情,除非我最近使用它。当您根据用户输入生成文档时,这将非常方便。
"<p>Some big paragraph ".$a["name"]." again have tot ake care of space and stuff .". $a["age"]. "also would be hard to keep track of punctuations and stuff in a really ".$a["token"]. paragarapoh.";
可以轻松写成
sprintf("Some big paragraph %s. Again have to take care of space and stuff.%s also wouldnt be hard to keep track of punctuations and stuff in a really %s paragraph",$a,$b,$c);
答案 9 :(得分:4)
此:
"<p>Some big paragraph ".$a["name"]." again have to take care of space and stuff .". $a["age"]. "also would be hard to keep track of punctuations and stuff in a really ".$a["token"]. paragraph.";
也可写:
"<p>Some big paragraph {$a['name']} again have to take care of space and stuff .{$a['age']} also would be hard to keep track of punctuations and stuff in a really {$a['token']} paragraph.";
在我看来,阅读更清楚,但我可以看到本地化或格式化的用途。
答案 10 :(得分:3)
我通常使用sprintf来确保来自用户输入的id是一个整数,例如:
// is better use prepared statements, but this is practical sometimes
$query = sprintf("SELECT * from articles where id = %d;",$_GET['article_id']);
还用于做基本模板(用于html邮件或其他东西),因此您可以在许多地方重复使用模板:
$mail_body = "Hello %s, ...";
$oneMail = sprintf($mail_body, "Victor");
$anotherMail = sprintf($mail_body, "Juan");
格式化不同表示形式的数字(八进制,控制小数位等)非常有用。
答案 11 :(得分:3)
有时我会得到这样的东西,我认为这更容易阅读:
$fileName = sprintf('thumb_%s.%s',
$fileId,
$fileInfo['extension']);
答案 12 :(得分:3)
define('TEXT_MESSAGE', 'The variable "%s" is in the middle!');
sprintf(TEXT_MESSAGE, "Var1");
sprintf(TEXT_MESSAGE, "Var2");
sprintf(TEXT_MESSAGE, "Var3");
答案 13 :(得分:3)
如果您使用过C / C ++,那么您将习惯使用sprintf函数。
第二行很可能效率较低。 Echo被设计为输出命令,而sprintf被设计为执行字符串标记替换。我不是PHP人员,但我怀疑回声涉及更多对象。如果它像Java一样,它会在每次向列表添加内容时创建一个新字符串,因此最终会创建4个字符串。
答案 14 :(得分:3)
sprintf特别有用。例如,
$oranges = -2.34;
echo sprintf("There are %d oranges in the basket", $oranges);
Output: There are -2 oranges in the basket
橙色被格式化为整数(-2),但如果使用%u作为无符号值,则会将其包围为正数。为了避免这种行为,我使用绝对函数abs()将数字舍入为零,如下所示:
$oranges = -5.67;
echo sprintf("There are %d oranges in the basket", abs($oranges));
Output: There are 5 oranges in the basket
最终结果是一个具有高可读性,逻辑结构,清晰格式以及根据需要添加其他变量的灵活性的语句。随着变量数量的增加以及操纵这些变量的函数的组合,其好处变得更加明显。作为最后一个例子:
$oranges = -3.14;
$apples = 1.5;
echo sprintf("There are %d oranges and %d apples", abs($oranges), abs($apples));
Output: There are 3 oranges and 4 apples
sprintf语句的左侧清楚地表达了字符串和期望值的类型,而右侧清楚地表达了使用的变量以及它们的操作方式。
答案 15 :(得分:3)
嗯,sprintf
具有我们所知的许多功能
如下例子:
几个月前,我需要将秒转换为小时:分钟:秒格式
就像$t = 494050 //seconds
我打算像137 h 14 m 10 s
一样打印所以我想出了php函数springf()
我只需要在$t
中保持秒数,echo sprintf("%02d h %s%02d m %s%02d s", floor($t/3600), $f, ($t/60)%60, $f, $t%60);
给我137 h 14 m 10 s
1}}
答案 16 :(得分:3)
有些典型案例需要您对输出格式进行更精确的控制。例如,确保特定值具有填充到前面的特定数量的空间(取决于其长度),或者以特定的精确格式输出数字,这可能是棘手的。
有很多例子in the PHP manual
你的“更容易写”的例子也是如此。虽然回声可能更容易编写,但sprintf更容易阅读,特别是如果你有很多变量。
使用sprintf或printf的另一个原因可能是您希望让用户定义某些值的输出格式 - 您可以安全地允许他们定义sprintf兼容的输出格式。
哦,你的例子实际上是错误的一部分。 sprintf
会返回字符串,但echo
没有 - echo
会立即输出该字符串并且不返回任何内容,而sprintf
只会返回该字符串。
答案 17 :(得分:2)
在普通级联上使用sprintf()函数的优点是可以对要连接的变量应用不同类型的格式。
在你的情况下,你有
$output = sprintf("Here is the result: %s for this date %s", $result, $date);
和
$output = 'Here is the result: ' .$result. ' for this date ' .$date;
我们来看$result = 'passed'; date = '23rd';
使用普通连接只能获得输出:
Here is the result: passed for this date 23rd
但是,如果您使用sprintf()
,则可以获得修改后的输出,例如:
$output = sprintf('Here is the result: %.4s for this date %.2s',$result,$date);
echo $output;
输出:
Here is the result: pass for this date 23
答案 18 :(得分:2)
该参数与使用模板的参数相同。您需要将Textsleev与实际变量值分开。除了sprintf的额外功能,我们提到它只是一种风格的东西。
答案 19 :(得分:2)
使用sprintf的一个非常好的用例是输出填充的数字格式,以及在字符串中混合使用不同类型时。在许多情况下可以更容易阅读,并且可以非常简单地打印同一变量的不同表示,尤其是数字变量。
答案 20 :(得分:1)
printf()
与printf()
非常相似。如果您详细了解sprintf()
,那么vsprintf()
甚至sprintf()
并不是很难理解。
printf()
与printf("Hello %s", "world"); // "Hello world"
sprintf("Hello %s", "world"); // does not display anything
echo sprintf("Hello %s", "world"); // "Hello world"
$a = sprintf("Hello %s", "world"); // does not display anything
echo $a;// "Hello world"
的不同之处之一是,您将需要声明一个变量以捕获函数的输出,因为它不会直接打印/回显任何内容。让我们看下面的代码片段:
dic1 = {'a':10,'b':2}
dic2 = {'a':20,'b':3}
dic3 = {'a':30,'c':'batman'}
pd.DataFrame(data=[dic1,dic2,dic3])
希望有帮助。
答案 21 :(得分:0)
答案 22 :(得分:0)
在循环中使用sprintf时必须小心:
$a = 'Anton';
$b = 'Bert';
$c = 'Corni';
$d = 'Dora';
$e = 'Emiel';
$f = 'Falk';
$loops = 10000000;
$time = microtime(true);
for ($i = 0; $i < $loops; $i++)
{
$test = $a . $b . $c . $d . $e . $f;
}
$concatTime = microtime(true) - $time;
$time = microtime(true);
for ($i = 0; $i < $loops; $i++)
{
$test = "$a $b $c $d $e $f";
}
$concat2Time = microtime(true) - $time;
$time = microtime(true);
for ($i = 0; $i < $loops; $i++)
{
$test = sprintf('%s %s %s %s %s %s', $a, $b, $c, $d, $e, $f);
}
$sprintfTime = microtime(true) - $time;
echo 'Loops: ' . $loops . '<br>';
echo '\'$a . $b . $c . $d . $e . $f\'' . ' needs ' . $concatTime . 's<br>';
echo '"$a $b $c $d $e $f"' . ' needs ' . $concat2Time . 's<br>';
echo 'sprintf(\'%s %s %s %s %s %s\', $a, $b, $c, $d, $e, $f)' . ' needs ' . $sprintfTime . 's<br>';
导致以下情况的时间(在使用PHP 7.2的本地计算机上):
环路:10000000
'$ a。 $ b。 $ c。 $ d。 $ e。 $ f'需要1.4507689476013s
“ $ a $ b $ c $ d $ e $ f”需要1.9958319664001s
sprintf('%s%s%s%s%s%s',$ a,$ b,$ c,$ d,$ e,$ f)需要9.1771278381348s
答案 23 :(得分:0)
我将其用于发送给用户或其他“漂亮”功能的消息。例如,如果我知道我将使用用户名。
$name = 'Some dynamic name';
在这种情况下可以使用多个消息。 (即阻止或关注另一个用户)
$messageBlock = 'You have blocked %s from accessing you.';
$messageFollow = 'Following %s is a great idea!';
您可以创建一个对用户执行某些操作的通用函数,并添加此字符串,无论句子的结构如何,它看起来都非常不错。我总是不喜欢仅将字符串附加在一起,并不断使用点符号以及关闭和重新打开字符串以使句子看起来不错。我一开始像大多数粉丝一样,但是当需要操纵多个字符串并且您不想每次都硬编码变量的位置时,这似乎很有用。
想到了,看起来什么更好?
return $messageOne === true ? $name.'. Please use the next example' : 'Hi '.$name.', how are you?'
或
$message = $messageOne === true ? 'Option one %s'
: ($messageTwo === true ? 'Option Two %s maybe?' : '%s you can choose from tons of grammatical instances and not have to edit variable placement and strings');
return sprintf($message, $name);
确保这是一个额外的步骤,但是如果您的条件检查执行了许多其他功能性的操作,那么引号和附加项就会开始妨碍功能性编码。