PHP Conference Japan 2024

sscanf

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

sscanf根據格式從字串解析輸入

說明

sscanf(字串 $string, 字串 $format, 混合 &...$vars): 陣列|整數|null

函式 sscanf()printf() 的輸入版本。sscanf() 從字串 string 讀取資料,並根據指定的 format 進行解譯。

格式字串中的任何空格都符合輸入字串中的任何空格。這表示即使格式字串中的定位字元 (\t) 也能符合輸入字串中的單個空格字元。

參數

string

要被解析的輸入 字串

format

用於解讀 string 的格式,其描述與 sprintf() 的文件說明相同,但以下列差異:

  • 此函式不具備語系感知能力(locale-aware)。
  • 不支援 FgGb
  • D 代表十進位數字。
  • i 代表自動偵測進位的整數。
  • 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
"產品 $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"
;
?>

另請參閱

新增註釋

使用者貢獻的註釋 16 則註釋

jon at fuck dot org
22 年前
這個函式是從 HTML 等效十六進位制值取得整數 RGB 值的好方法。

list($r, $g, $b) = sscanf('00ccff', '%2x%2x%2x');
elgabos at umail dot ucsb dot edu
22 年前
在玩了一段時間之後,我發現如果使用 %[^[]] 而不是 %s(因為 PHP 在使用 %s 時會出現空格問題),它就能正常運作。

對於不熟悉正規表示式的人來說,%[^[]] 基本上會匹配任何非空字元。

希望這有幫助。 - Gabe
mikewillitsgmail.com
16 年前
僅供參考 - 如果您嘗試從包含帶副檔名的檔案名的字串進行掃描。例如

<?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
Brainiac361
19 年前
`%[^[]` 的技巧看似有效,但實際上並非如此!

`sscanf` 只會匹配任何不是左方括號的字元(這種情況相當少見,所以它可能看起來有效)。
但更糟的是,它會接著預期一個 `]` 字元,然後繼續匹配任何字元。

你可以做的是讓 `sscanf` 尋找任何不是真正從未使用的字元的字元……一個好的選擇是換行符號 `%[^\\n]`,尤其是在與 `fscanf` 結合使用時。

你也可以複製並貼上任何未使用的 ASCII 字元,例如 #001 或其他類似字元。
leg
16 年前
@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" 時出現錯誤結果!
codeslinger at compsalot dot com
19 年前
安全性注意事項

雖然這是一個非常強大的技巧,但請記住,它很容易被欺騙。

許多成功的漏洞利用都是基於 scanf 攻擊。不應在未經大量額外驗證的情況下將其用於不受信任的輸入。
Vincent Jansen
19 年前
如果您只想篩選出字串兩個部分之間的資訊,我使用了以下方法,它對我來說比 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");
?>
匿名用戶
18 年前
我看過幾個例子,人們使用方括號來定義看起來像正規表達式字元類別的東西。在我有限的測試中,我不認為它們是真正的字元類別,但它們看起來很相似。

我的任務是使用 sscanf() 解析格式如下的字串陣列:

數字 空格 可能也包含空格的字串

一般的 %s 轉換指令會將空格視為某種分隔符號。因此,如果您事先知道會有多少個「單詞」,就可以取得字串。但是,我的輸入是可變的。

以下是我想出的方法:(請注意使用錢字號 '$' 作為隱藏的字串結尾分隔符號)

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

這個轉換指令表示「尋找一個整數,然後是一個空格,然後是到字串結尾的任何字串」
skeltoac
18 年前
解析通用格式的 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']
);
?>
Victor
12 年前
需要注意的一點是:與 C/C++ 不同,分配給 %n 變數的值會被計入返回值中。
narainsbrain at yahoo dot com
23 年前
顯然地,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() 函式。
Philo
4 年前
還需要注意的是,當與 sscanf 一起使用時,x 和 X 會產生相同的輸出(即它們不區分大小寫)。

<?php
var_dump
(sscanf("0xdead|0XDEAD", "%X|%x")); // 正常運作
joshmckenneyATgmailDOT(0{
19 年前
在電話號碼函式中加入了國家代碼 (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;
}
clcollie at mindspring dot com
24 年前
實際上,如果你指定的回傳變數少於格式指定符,sscanf() 總是會回傳一個陣列。我可能會將其更改為如果只有一個格式指定符,則回傳一個純量值。
請注意,sscanf()(幾乎)與其「C 語言」版本的功能完全相同,因此你可以執行以下操作來獲得預期的效果

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

陣列回傳是 PHP 的一個優點。
marcus at synchromedia dot co dot uk
21 年前
在 PHP >= 4.3.0 中,如果你使用額外的參考參數,你會收到以下警告

PHP 警告:呼叫時傳遞參考已被棄用 - 參數以值傳遞

這顯然有可能導致意想不到的後果(變數保持空白),並且會破壞現有的程式碼。所以不要這樣做!這些文件也需要更新以說明這一點。

語法

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

將會按預期工作,並且在我注意到的情況下似乎不會對 Apache 造成任何問題。
sbarnum.pointsystems@com
22 年前
電話號碼的更多樂趣!這裡假設電話號碼是 10 位數,且僅包含數字數據,但可以很容易地先檢查字串的長度。

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