此函数是获取 HTML 等效十六进制的整数 RGB 值的好方法。
list($r, $g, $b) = sscanf('00ccff', '%2x%2x%2x');
(PHP 4 >= 4.0.1, PHP 5, PHP 7, PHP 8)
sscanf — 根据格式解析来自字符串的输入
函数 sscanf() 是 printf() 的输入模拟。 sscanf() 从字符串 string
读取并根据指定的 format
进行解释。
格式字符串中的任何空格都匹配输入字符串中的任何空格。这意味着,即使格式字符串中的制表符 (\t
) 也可以匹配输入字符串中的单个空格字符。
如果仅将两个参数传递给此函数,则解析的值将作为数组返回。否则,如果传递了可选参数,则函数将返回已赋值值的数目。可选参数必须按引用传递。
如果 format
中期望的子字符串多于 string
中可用的子字符串,则将返回 null
。
示例 #1 sscanf() 示例
<?php
// 获取序列号
list($serial) = sscanf("SN/2350001", "SN/%d");
// 以及制造日期
$mandate = "January 01 2000";
list($month, $day, $year) = sscanf($mandate, "%s %d %d");
echo "物品 $serial 制造于:$year-" . substr($month, 0, 3) . "-$day\n";
?>
如果传递了可选参数,则函数将返回已赋值值的数目。
示例 #2 sscanf() - 使用可选参数
<?php
// 获取作者信息并生成 DocBook 条目
$auth = "24\tLewis Carroll";
$n = sscanf($auth, "%d\t%s %s", $id, $first, $last);
echo "<author id='$id'>
<firstname>$first</firstname>
<surname>$last</surname>
</author>\n";
?>
此函数是获取 HTML 等效十六进制的整数 RGB 值的好方法。
list($r, $g, $b) = sscanf('00ccff', '%2x%2x%2x');
在玩了一段时间之后,我发现如果你使用 %[^[]] 而不是 %s(因为 php 在使用 %s 时存在空格问题),它可以很好地工作。
对于那些不熟悉正则表达式的人,%[^^] 基本上匹配任何不是空的东西。
希望这有帮助。- Gabe
仅供参考 - 如果你试图从包含带有扩展名的文件名的字符串中扫描。例如
<?php
$out = sscanf('file_name.gif', 'file_%s.%s', $fpart1, $fpart2);
?>
在 $fpart1 参数中扫描的字符串结果为 'name.gif',而 $fpart2 将为 NULL。
要解决此问题,你可以简单地将 "." 替换为空格或其他“类似空格”的字符串序列。
我没有看到关于包含“.”的字符串文字的其他任何评论,所以我认为我应该提一下。我认为具有“空格分隔”内容的细微特征可能是使用争论的根源。显然,另一种方法是在这种情况下使用正则表达式,但对于新用户来说,这可能会有所帮助。
以防万一其他人像我一样花了 10 分钟的沮丧时间。这在 PHP 版本 5.2.3-1ubuntu6.3 上看到。
搜索错误报告显示另一位用户的误解:http://bugs.php.net/bug.php?id=7793
%[^^] 技巧可能看起来有效,但它无效!
发生的情况是,sscanf 将简单地匹配除开括号 [ 以外的任何字符(这比较罕见,因此它可能看起来正常工作)。
但更糟糕的是,它会期望接下来出现一个 ] 字符,并继续匹配任何内容。
现在,您可以做的是让 sscanf 查找除一个实际上从未使用过的字符以外的任何字符……一个不错的选择是换行符 "%[^\\n]",尤其是在与 fscanf 结合使用时。
您还可以做的是复制粘贴任何未使用的 ASCII 字符,例如 #001 或其他字符。
@mikewillitsgmail.com
<?php
$out = sscanf('file_name.gif', 'file_%[^.].%s', $fpart1, $fpart2);
echo '<pre>';
print_r($fpart1);
echo '<hr />';
print_r($fpart2);
echo '</pre>';
?>
输出
name
-
gif
"^." 部分避免了第一个搜索字符串过于贪婪。但无法防止 "file_test.name.gif" 这样的输入,会导致错误的结果!
安全提示
虽然这是一种非常强大的技术,但请记住它很容易被欺骗。
许多成功的漏洞利用都是基于 scanf 攻击。在没有进行大量额外验证的情况下,不应将其用于不受信任的输入。
如果您只想过滤掉字符串中两个部分之间的信息,我使用了以下方法,它对我来说比 sscanf 函数效果更好。
<?php
function scanstr($zoekstr,$part1,$part2) {
$firstpos=strpos ($zoekstr, $part1)+strlen($part1);
$lastpos=strpos ($zoekstr, $part2);
$scanresult=substr ($zoekstr, $firstpos, $lastpos-$firstpos);
return($scanresult);
}
echo scanstr ("var1=hello&var2=test&var3=more","var2=","&var3");
?>
我见过一些使用括号定义看起来像正则表达式字符类的示例。在我有限的测试中,我认为它们不是真正的字符类,但它们似乎很相似。
我的任务是使用 sscanf() 解析格式为以下格式的字符串数组:
数字 空格 可能也包含空格的字符串
普通的 %s 转换命令将空格视为某种分隔符。因此,如果您事先知道会有多少个“单词”,则可以获取字符串。但是,我的输入是可变的。
这是我想出的方法:(注意使用了美元符号“字符串结束”隐藏分隔符)
sscanf($string_to_parse,'%d %[^$]s',$num,$text);
此转换命令表示“查找一个整数,然后是一个空格,然后是直到字符串结束的任何字符串”
解析以通用格式存储在 Apache 访问日志中的行
<?php
$log = array();
$n = sscanf(trim($line), '%s %s %s [%[^]]] "%s %s %[^"]" %d %s "%[^"]" "%[^"]"',
$log['ip'],
$log['client'],
$log['user'],
$log['time'],
$log['method'],
$log['uri'],
$log['prot'],
$log['code'],
$log['bytes'],
$log['ref'],
$log['agent']
);
?>
显然,sscanf 总是以空格分割,即使格式中未指定空格。考虑以下脚本
<?php
$str = "This is a\tsentence with\ttabs";
$scanned = sscanf($str, "%s\t%s\t%s");
echo join(" : ", $scanned);
?>
这会输出 "This : is : a",而不是预期的 "This is a : sentence with : tabs."。
如果您的字符串不包含空格,此行为是可以的,但如果包含空格,则最好使用 explode()。
还应注意,当与 sscanf 一起使用时,x 和 X 会产生相同的输出(即,它们不区分大小写)。
<?php
var_dump(sscanf("0xdead|0XDEAD", "%X|%x")); // works
在电话号码函数中添加了国家代码 (1)
function formatPhone($phone) {
if (empty($phone)) return "";
if (strlen($phone) == 7)
sscanf($phone, "%3s%4s", $prefix, $exchange);
else if (strlen($phone) == 10)
sscanf($phone, "%3s%3s%4s", $area, $prefix, $exchange);
else if (strlen($phone) > 10)
if(substr($phone,0,1)=='1') {
sscanf($phone, "%1s%3s%3s%4s", $country, $area, $prefix, $exchange);
}
else{
sscanf($phone, "%3s%3s%4s%s", $area, $prefix, $exchange, $extension);
}
else
return "unknown phone format: $phone";
$out = "";
$out .= isset($country) ? $country.' ' : '';
$out .= isset($area) ? '(' . $area . ') ' : '';
$out .= $prefix . '-' . $exchange;
$out .= isset($extension) ? ' x' . $extension : '';
return $out;
}
实际上,如果您指定的返回值变量少于格式说明符,sscanf() _始终_ 返回一个数组。如果只存在一个格式说明符,我可能会将其更改为返回标量。
请注意,sscanf()(几乎)与其“C”对应部分具有完全相同的功能,因此您可以执行以下操作以获得预期的效果
sscanf("SN/2350001","SN/%d",&$serial)
数组返回是 PHP 的一个优点。
在 PHP >= 4.3.0 中,如果您使用额外的引用参数,您将收到此警告
PHP Warning: Call-time pass-by-reference has been deprecated - argument passed by value
这显然有可能导致意外后果(变量为空),并且会破坏现有代码。所以不要这样做!这些文档也需要更新以说明这一点。
语法
list($a, $b) = sscanf("hello world", "%s %s");
将按预期工作,并且似乎没有导致我注意到的任何 Apache 问题。
更多关于电话的乐趣!这假设电话号码是 10 位数字,并且仅包含数字数据,但可以很容易地首先检查字符串的长度。
function formatPhone($phone) {
if (empty($phone)) return "";
sscanf($phone, "%3d%3d%4d", $area, $prefix, $exchange);
$out = @$area ? "($area) " : "";
$out .= $prefix . '-' . $exchange;
return $out;
}