sscanf字符串提取


function
<cstdio>
sscanf
int sscanf ( const char * s, const char * format, ...);
Read formatted data from string
Reads data from s and stores them according to parameter format into the locations given by the additional arguments, as if scanf was used, but reading from s instead of the standard input (stdin).

The additional arguments should point to already allocated objects of the type specified by their corresponding format specifier within the format string.

Parameters
s
C string that the function processes as its source to retrieve the data.
format
C string that contains a format string that follows the same specifications as format in scanf (see scanf for details).
... (additional arguments)
Depending on the format string, the function may expect a sequence of additional arguments, each containing a pointer to allocated storage where the interpretation of the extracted characters is stored with the appropriate type.
There should be at least as many of these arguments as the number of values stored by the format specifiers. Additional arguments are ignored by the function.

Return Value
On success, the function returns the number of items in the argument list successfully filled. This count can match the expected number of items or be less (even zero) in the case of a matching failure.
In the case of an input failure before any data could be successfully interpreted, EOF is returned.

 

函數原型:
int sscanf( const  char *, const char *, ...);
int sscanf(const char *buffer,const char *format,[argument ]...);
buffer存儲的數據
format格式控制字符串
argument 選擇性設定字符串
sscanf會從buffer里讀進數據,依照format的格式將數據寫入到argument里。

頭文件

#include<stdio.h> 或者
#include <cstdio>

返回值

成功則返回參數數目,失敗則返回-1,錯誤原因存於 errno中。
經多次測試[來源請求], 在linux系統中成功返回的是成功轉換的值的個數,例如:
sscanf("1 2 3","%d %d %d",buf1, buf2, buf3); 成功調用返回值為3,即buf1,buf2,buf3均成功轉換。
sscanf("1 2","%d %d %d",buf1, buf2, buf3); 成功調用返回值為2,即只有buf1,buf2成功轉換。
(注意:此處buf均為地址)

sscanf與scanf類似,都是用於輸入的,只是后者以鍵盤(stdin)為輸入源,前者以固定字符串為輸入源。

格式控制符,類似於正則表達式:

sscanf的第二個參數可以是一個或多個 {%[*] [width] [{h | I | I64 | L}]type | ' ' | '\t' | '\n' | 非%符號}
注:
1、 * 亦可用於格式中, (即 %*d 和 %*s) 加了星號 (*) 表示跳過此數據不讀入. (也就是不把此數據讀入參數中)
2、{a|b|c}表示a,b,c中選一,[d],表示可以有d也可以沒有d。
3、width表示讀取寬度。
4、{h | l | I64 | L}:參數的size,通常h表示單字節size,I表示2字節 size,L表示4字節size(double例外),l64表示8字節size。
5、type :這就很多了,就是%s,%d之類。
6、特別的:%*[width] [{h | l | I64 | L}]type 表示滿足該條件的被過濾掉,不會向目標參數中寫入值
失敗返回0 ,否則返回格式化的參數個數

支持集合操作

%[a-z] 表示匹配a到z中任意 字符,貪婪性(盡可能多的匹配)
%[aB'] 匹配a、B、'中一員,貪婪性
%[^a] 匹配非a的任意字符,並且停止讀入,貪婪性

例子

1. 常見用法。
1
2
3
char  buf[512];
sscanf ( "123456" , "%s" ,buf); //此處buf是數組名,它的意思是將123456以%s的形式存入buf中!
printf ( "%s\n" ,buf);
結果為:123456
2. 取指定長度的 字符串。如在下例中,取最大長度為4 字節的字符串。
1
2
sscanf ( "123456" , "%4s" ,buf);
printf ( "%s\n" ,buf);
結果為:1234
3. 取到指定字符為止的字符串。如在下例中,取遇到任意小寫字母為止的字符串。
1
2
sscanf ( "123456abcdedf" , "%[^a-z]" ,buf);
printf ( "%s\n" ,buf);
結果為:123456
4. 取僅包含指定字符集的字符串。如在下例中,取僅包含1到9和小寫字母的字符串。
1
2
sscanf ( "123456abcdedfBCDEF" , "%[1-9a-z]" ,buf);
printf ( "%s\n" ,buf);
結果為:123456abcdedf
當輸入:  sscanf("123456abcdedfBCDEF","%[1-9A-Z]",buf);
1
printf ( "%s\n" ,buf);
結果為:123456BCDEF(錯!!)
注:結果應該為:123456【因為遇到不是1-9或者A-Z的字符時,即遇到小寫字母時,就已經結束】
5. 取到指定字符集為止的字符串。如在下例中,取遇到大寫字母為止的字符串。
1
2
sscanf ( "123456abcdedfBCDEF" , "%[^A-Z]" ,buf);
printf ( "%s\n" ,buf);
結果為:123456abcdedf
6、給定一個字符串iios/12DDWDFF@122,獲取 / 和 @ 之間的字符串,
先將 "iios/"過濾掉,再將非'@'的一串內容送到buf中
1
2
sscanf ( "iios/12DDWDFF@122" , "%*[^/]/%[^@]" ,buf);
printf ( "%s\n" ,buf);
結果為:12DDWDFF
7、給定一個字符串“hello, world”,僅保留world。
(注意:“,”之后有一空格,%s遇空格停止,加*則是忽略第一個讀到的字符串)
1
2
sscanf (“hello, world”, "%*s%s" ,buf);
printf ( "%s\n" ,buf);
結果為:world
%*s表示第一個匹配到的%s被過濾掉,即“hello,”被過濾了
如果沒有空格則結果為NULL。
8、最簡明的格式是tab間隔的字符串
1
2
sscanf (“字符串1\t字符串2\t字符串3”, "%s%s%s" ,str1,str2,str3);
printf ( "%s\t%s\t%s\n" ,str1,str2,str3);
結果為:字符串1 字符串2 字符串3
 

sscanf及sscanf_s的常用方法,原來安全版本的函數,對參數和緩沖邊界做了檢查,增加了返回值和拋出異常。這樣增加了函數的安全性,減少了出錯的幾率。
同時這也意味着在使用這些函數時,有時你不得不輸入更多的關於緩沖區大小的參數,多敲幾下鍵盤能換來更少的麻煩,值得!

下面總結了sscanf的以及sscanf_s的常用方法,也體現了“_s”版本函數與原函數的特別之處:

1、sscanf和scanf的不同是輸入來源,前者是一個字符串,后者則是標准輸入設備

2、sscanf的使用,以解析時間字符串為例,將字符串“2009-01-02_11:12:13”解析為整型年月日時分秒

//定義
 char cc;
 tm tm_temp={0};
 string stime("2009-01-02_11:12:13");

(1) 必須嚴格按照分隔符形式匹配填寫,若遇到不匹配項則終止解析

 sscanf(stime.c_str(), "%4d-%2d-%2d_%2d:%2d:%2d",
  &tm_temp.tm_year, 
  &tm_temp.tm_mon, 
  &tm_temp.tm_mday, 
  &tm_temp.tm_hour, 
  &tm_temp.tm_min, 
  &tm_temp.tm_sec
  );
(2) 可以不按照分割符號形式填寫,字符數必須一致,例如可以正確解析“2009/01/02_11:12:13”

 sscanf(stime.c_str(), "%4d%c%2d%c%2d%c%2d%c%2d%c%2d",
  &tm_temp.tm_year, &cc,
  &tm_temp.tm_mon, &cc,
  &tm_temp.tm_mday, &cc,
  &tm_temp.tm_hour, &cc,
  &tm_temp.tm_min, &cc,
  &tm_temp.tm_sec
  );
 
(3) 可以不按照分割符號形式填寫,字符數必須一致,同上,%1s可以等同於%c

 sscanf(stime.c_str(), "%4d%1s%2d%1s%2d%1s%2d%1s%2d%1s%2d",
  &tm_temp.tm_year, &cc,
  &tm_temp.tm_mon, &cc,
  &tm_temp.tm_mday, &cc,
  &tm_temp.tm_hour, &cc,
  &tm_temp.tm_min, &cc,
  &tm_temp.tm_sec
  );

(4) 可以不按照分割符形式和數量填寫,類型必須一致,例如可以正確解析“2009/01/02___11:12:13”
這里使用了sscanf的正則表達式,與通用的正則表示類似但不完全相同,%*c表示忽略連續多個字符

 sscanf(stime.c_str(), "%4d%*c%2d%*c%2d%*c%2d%*c%2d%*c%2d",
  &tm_temp.tm_year, 
  &tm_temp.tm_mon, 
  &tm_temp.tm_mday, 
  &tm_temp.tm_hour, 
  &tm_temp.tm_min, 
  &tm_temp.tm_sec
  );
  
3、sscanf_s的使用

 //定義
 char cc[2];
 tm tm_temp={0};
 string stime("2009-01-02_11:12:13");

(1) 與sscanf第一種方法相同,可以使用"%4d-%2d-%2d_%2d:%2d:%2d"格式匹配解析

 sscanf_s(stime.c_str(), "%4d-%2d-%2d_%2d:%2d:%2d",
   &tm_temp.tm_year, 
   &tm_temp.tm_mon, 
   &tm_temp.tm_mday, 
   &tm_temp.tm_hour, 
   &tm_temp.tm_min, 
   &tm_temp.tm_sec
   );
(2) 使用%c格式對數據解析時,必須對相應的緩沖區增加長度參數,否則將會出錯

 sscanf_s(stime.c_str(), "%4d%c%2d%c%2d%c%2d%c%2d%c%2d",
  &tm_temp.tm_year, &cc, 1,
  &tm_temp.tm_mon, &cc, 1,
  &tm_temp.tm_mday, &cc, 1,
  &tm_temp.tm_hour, &cc, 1,
  &tm_temp.tm_min, &cc, 1,
  &tm_temp.tm_sec
  );
(3) 使用%s格式對數據解析時,緩沖長度必須大於字符串長度,否則不予解析

 sscanf_s(stime.c_str(), "%4d%1s%2d%1s%2d%1s%2d%1s%2d%1s%2d",
   &tm_temp.tm_year, &cc, 2,
   &tm_temp.tm_mon, &cc, 2,
   &tm_temp.tm_mday, &cc, 2,
   &tm_temp.tm_hour, &cc, 2,
   &tm_temp.tm_min, &cc, 2,
   &tm_temp.tm_sec
   );

(4) 與sscanf一樣,sscanf_s同樣支持正則表達式

 sscanf_s(stime.c_str(), "%4d%*c%2d%*c%2d%*c%2d%*c%2d%*c%2d",
  &tm_temp.tm_year, 
  &tm_temp.tm_mon, 
  &tm_temp.tm_mday, 
  &tm_temp.tm_hour, 
  &tm_temp.tm_min, 
  &tm_temp.tm_sec
  );
通過以上對比sscanf與sscanf_s的使用,可以看出后者對緩沖區安全有了更多的考慮,從而避免了許多不經意的煩惱。

大家都知道sscanf是一個很好用的函數,利用它可以從字符串中取出整數、浮點數和字符串等等。它的使用方法簡單,特別對於整數和浮點數來說。但新手可 能並不知道處理字符串時的一些高級用法,這里做個簡要說明吧。

 

#include <stdio.h>
#include <string.h>

int main() {

    char input[] = "{\"Vesion\":1.0,\"cmd\":\"live\",\"data\":{\"action\":\"play\",\"params\" : [{\"type\":\"video1\",\"media_ip\":\"192.168.89.4\",\"channel\":1}]}}";

    char ip[16];
    int stream;

    char *pstr = strstr(input, "media_ip");
    printf("pstr=%s\n",pstr+11);
    int ret=sscanf(strstr(input,"media_ip")+11, "%[0-9.]%*[^:]:%d[0-9]",ip,&stream);  // 這里必須是取地址
    printf("ret=%d,ip=%s,stream=%d\n",ret,ip,stream);

    printf("Over");
    getchar();
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM