此函数是将 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 "Item $serial was manufactured on: $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")); // 工作
在电话号码函数中添加了国家代码 (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 "未知电话格式: $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 警告:调用时按引用传递已弃用 - 参数按值传递
这显然有可能导致意外后果(变量为空),并且会破坏现有代码。 所以不要这样做! 这些文档也需要更新以说明这一点。
语法
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;
}
这更像是 C/C++ 示例,但在 PHP 中也能正常工作。
<?php
$qs = "index.php?id=34&name=john";
print_r( sscanf($qs, "%[^?]?%[^?]") );
$qs = "id=34&name=john";
print_r( sscanf($qs, "id=%[^&]&name=%[^&]") );
?>
解析具有固定字段大小的输入字符串,其中包含带有空格的数据
<?php
$result = sscanf(" Vendor: My Vendo Model: Super Model Foo Rev: 1234",
' Vendor: %8[ -~] Model: %16[ -~] Rev: %4c',
$vendor, $model, $rev);
?>
$vendor => My Vendo
$model => Super Model Foo
$rev => 1234