sscanf

(PHP 4 >= 4.0.1, PHP 5, PHP 7, PHP 8)

sscanf根据指定格式解析输入的字符

说明

sscanf(string $string, string $format, mixed &...$vars): array|int|null

sscanf() 函数输入类似 printf()sscanf() 读取字符串 string,然后根据指定格式 format 解析。

指定的格式字符串中的任意空白匹配输入字符串的任意空白。也就是说即使是格式字符串中的一个制表符(\t)也能匹配输入字符串中的单个空白字符。

参数

string

将要被解析的 string

format

string 的格式解释,在 sprintf() 的文档中进行了描述,但有以下区别:

  • 函数不支持区域设置。
  • 不支持 FgGb
  • D 代表十进制数字。
  • i stands for integer with base detection.
  • n 代表到目前为止处理的字符数。
  • s 在任何空白字符处停止阅读。
  • * 代替 argnum$ 禁止分配此转换规范。

vars

可选参数将以引用方式传入,它们的值将被设置为解析值。

返回值

如果仅传入了两个参数给这个函数,解析后的值作为数组返回。否则,如果传入可选参数,函数将返回赋值数量。可选参数必须通过引用传递。

如果 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"
;
?>

参见

添加备注

用户贡献的备注 16 notes

up
69
jon at fuck dot org
22 years ago
this function is a great way to get integer rgb values from the html equivalent hex.

list($r, $g, $b) = sscanf('00ccff', '%2x%2x%2x');
up
17
elgabos at umail dot ucsb dot edu
22 years ago
After playing around with this for a while, I found that if you use %[^[]] instead of %s (since php has problems with spaces when using %s) it works nicely.

For those that aren't familiar with regular expressions, %[^[]] basically matches anything that isn't nothing.

Hope this helps. - Gabe
up
16
mikewillitsgmail.com
16 years ago
FYI - if you are trying to scan from a string which contains a filename with extension. For instance:

<?php

$out
= sscanf('file_name.gif', 'file_%s.%s', $fpart1, $fpart2);

?>

The scanned string in the $fpart1 parameter turns out to be 'name.gif' and $fpart2 will be NULL.

To get around this you can simply replace the "." with a space or another "white-space like" string sequence.

I didn't see any other comments on regarding string literals which contain a '.' so I thought I'd mention it. The subtle characteristics of having "white-space delimited" content I think can be a source of usage contention. Obviously, another way to go is regular expressions in this instance, but for newer users this may be helpful.

Just in case someone else spent 10 minutes of frustration like I did. This was seen on PHP Version 5.2.3-1ubuntu6.3.

Searching the bug reports shows another users misunderstanding: http://bugs.php.net/bug.php?id=7793
up
4
Brainiac361
19 years ago
The %[^[]]-trick may seem to work, but it doesn't!

What happens is that sscanf will simply match any characters but an opening square bracket (which is rather rare and that's why it might just seem to work).
But even worse it will expect a ]-character next and continue to match anything.

Now what you can do is make sscanf look for any character but a character that is really never used... a good choice is the linebreak "%[^\\n]", especially in combination with fscanf.

What you can also do is copy and paste any unused ascii character like #001 or something.
up
6
leg
16 years ago
@mikewillitsgmail.com:

<?php

$out
= sscanf('file_name.gif', 'file_%[^.].%s', $fpart1, $fpart2);

echo
'<pre>';
print_r($fpart1);
echo
'<hr />';
print_r($fpart2);
echo
'</pre>';

?>

output:

name
-
gif

The "^." part avoid the first searched string to be too greedy. But doesn't protect you against an "file_test.name.gif" input, with bad results!
up
3
codeslinger at compsalot dot com
19 years ago
Security Note:

Although it is a very powerful technique, keep in mind that it is easily deceived.

Many successful exploits have been based on scanf attacks. It should not be used on untrusted input without a lot of additional validation.
up
3
Vincent Jansen
19 years ago
If you just wants filter out information between two parts of a string, i used the following, it works better for me then the sscanf function.

<?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");
?>
up
2
anonymouse
18 years ago
I've seen several examples of people using brackets to define what look like regexp character classes. In my limited testing I don't think they are genuine character classes but they seem to be similar.

My task was to use sscanf() to parse an array of strings with the format:

number SPACE string_which_may_also_have_spaces

The normal %s conversion command treats spaces as some kind of delimiter. So, you can get the strings if you know beforehand how many "words" there will be. But, my input was variable.

Here's what I came up with: (note use of the dollar-sign 'end of string' hidden delimiter)

sscanf($string_to_parse,'%d %[^$]s',$num,$text);

This conversion command says "look for an integer, then a space, then any string up to the end of the string"
up
2
skeltoac
18 years ago
To parse a line from an Apache access log in common format:

<?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']
);
?>
up
2
Victor
12 years ago
One thing to note: unlike C/C++, a variable %n is assigned to will be counted in the return value.
up
2
narainsbrain at yahoo dot com
23 years ago
apparently, sscanf always splits at spaces, even if spaces are not specified in the format. consider this script:

<?php
$str
= "This is a\tsentence with\ttabs";
$scanned = sscanf($str, "%s\t%s\t%s");
echo
join(" : ", $scanned);
?>

this echoes "This : is : a", not the expected "This is a : sentence with : tabs."
this behaviour is fine if your strings don't contain spaces, but if they do you'd be better off using explode().
up
0
Philo
4 years ago
It should also be noted that when used with sscanf both x and X produce the same output (i.e. they are case-insensitive).

<?php
var_dump
(sscanf("0xdead|0XDEAD", "%X|%x")); // works
up
0
joshmckenneyATgmailDOT(0{
19 years ago
added country code (1) to phone number function:

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;
}
up
-1
clcollie at mindspring dot com
24 years ago
Actually sscanf()_always_ returns an array if you specify less return variables than format specifiers. i may change this to return a scalar if only a single format specifier exists.
Note that sscanf() is (almost) the complete functional equivalent of its "C" counterpart, so you can do the following to get the expected effect :

sscanf("SN/2350001","SN/%d",&$serial)

The array return was a nicety for PHP.
up
-3
marcus at synchromedia dot co dot uk
21 years ago
In PHP >= 4.3.0, if you use additional reference parameters, you will get this warning:

PHP Warning: Call-time pass-by-reference has been deprecated - argument passed by value

This clearly has the potential to cause unexpected consequences (vars left empty), and will break existing code. So don't do it! These docs need updating to say this too.

The syntax:

list($a, $b) = sscanf("hello world", "%s %s");

will work as expected, and doesn't seem to cause any problems with Apache that I've noticed.
up
-4
sbarnum.pointsystems@com
22 years ago
More fun with phones! This assumes that the phone number is 10 digits, with only numeric data, but it would be easy to check the length of the string first.

function formatPhone($phone) {
if (empty($phone)) return "";
sscanf($phone, "%3d%3d%4d", $area, $prefix, $exchange);
$out = @$area ? "($area) " : "";
$out .= $prefix . '-' . $exchange;
return $out;
}
To Top