zoukankan      html  css  js  c++  java
  • sscanf用法

    定义函数     int sscanf (const char *str,const char * format,........);

    函数说明     sscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据。格式转换形式请参考scanf()。转换后的结果存于对应的参数内。

    返回值     成功则返回匹配成功的参数数目,失败则返回-1,错误原因存于errno中。

    范例     #include<stdio.h>
    main()
    {
    int i;
    unsigned int j;
    char input[ ]=”10 0x1b aaaaaaaa bbbbbbbb”;
    char s[5];
    sscanf(input,”%d %x %5[a-z] %*s %f”,&i,&j,s,s);
    printf(“%d %d %s ”,i,j,s);

    大家都知道sscanf是一个很好用的函数,利用它可以从字符串中取出整数、浮点数和字符串等等。它的使用方法简单,特别对于整数和浮点数来说。但新手可能并不知道处理字符串时的一些高级用法,这里做个简要说明吧。
    1.         常见用法。
    charstr[512] = {0};
             sscanf("123456 ", "%s", str);
        printf("str=%s ", str);
    2.         取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。
        sscanf("123456 ", "%4s", str);
        printf("str=%s ", str);
    3.         取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。
        sscanf("123456 abcdedf", "%[^ ]s", str);
        printf("str=%s ", str);
    4.         取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
        sscanf("123456abcdedfBCDEF", "%[1-9a-z]s", str);
        printf("str=%s ", str);
    5.         取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。
        sscanf("123456abcdedfBCDEF", "%[^A-Z]s", str);
        printf("str=%s ", str);

    sscanf可以支持格式字符%[] 这为分析字符串提供了很大方便(其实scanf也支持%[])

    先看一下%[] 格式:
    (1)-: 表示范围,如:%[1-9]表示只读取1-9这几个数字 %[a-z]表示只读取a-z小写字母,类似地 %[A-Z]只读取大写字母
    (2)^: 表示不取,如:%[^1]表示读取除‘1‘以外的所有字符 %[^/]表示除/以外的所有字符
    (3),: 范围可以用","相连接 如%[1-9,a-z]表示同时取1-9数字和a-z小写字母 
    (4)原则:从第一个在指定范围内的数字开始读取,到第一个不在范围内的数字结束%s 可以看成%[] 的一个特例 %[^ ](注意^后面有一个空格!)

    这样使用sscanf+%[]可以轻松的分析字符串,很多字符串问题便迎刃而解了。
    以hrbeu3001为例(不是完整代码,没有要求的格式)
    只需2个sscanf函数,就能完成题目的要求,代码非常简洁。
    #include <stdio.h>
    #include <string.h>

    int main(int argc, char *argv[])
    {
         char buf[1024],str1[100],str2[100],str3[100],str4[100],temp[100]="<default>";
      
         int count;
         scanf("%d",&count);
         while(count--)
         {
            str1[0]=‘‘;
            str2[0]=‘‘;
            str3[0]=‘‘;
            str4[0]=‘‘;
            scanf("%s",buf);
            sscanf(buf,"%[^:]://%[^:,/]:%[,1-9]",str1,str2,str3,str4);
            sscanf(buf,"%[^:]://%[^:,/]/%[a-z,A-Z,/,~]",str1,str2,str4);
            if(str3[0]==‘‘)strcpy(str3,temp);
            if(str4[0]==‘‘)strcpy(str4,temp);
            printf("%s %s %s %s ",str1,str2,str3,str4);
         }
         return 0;
    }

    ========================================================

    此文所有的实验都是基于下面的程序:

    char str[10];

    for (int i = 0; i < 10; i++) str[i] = '!';

    执行完后str的值为

    str = "!!!!!!!!!!"

    我们把str的每个字符都初始化为惊叹号,当str的值发生变化时,使用printf打印str的值,对比先前的惊叹号,这样就可以方便的观察str发生了怎样的变化。下面我们做几个小实验,看看使用sscanf和正则表达式格式化输入后,str有什么变化。

    实验1:

    sscanf("123456","%s",str); ---------str的值为 "123456!!!"

    这个实验很简单,把源字符串"123456"拷贝到str的前6个字符,并且把str的第7个字符设为null字符,也就是

    实验2:

    sscanf("123456","%3s",str); ---------str的值为 "123!!!!!!"

    看到没有,正则表达式的百分号后面多了一个3,这告诉sscanf只拷贝3个字符给str,然后把第4个字符设为null字符。

    实验3:

    sscanf("aaaAAA","%[a-z]",str); ---------str的值为 "aaa!!!!!!"

    从这个实验开始我们会使用正则表达式,括号里面的a-z就是一个正则表达式,它可以表示从a到z的任意字符,

    在 继续讨论之前,我们先来看看百分号表示什么意思,%表示选择,%后面的是条件,比如实验1的"%s",s是一个条件,表示任意字符,"%s"的意思是:只 要输入的东西是一个字符,就把它拷贝给str。实验2的"%3s"又多了一个条件:只拷贝3个字符。实验3的“%[a-z]”的条件稍微严格一些,输入的 东西不但是字符,还得是一个小写字母的字符,所以实验3只拷贝了小写字母"aaa"给str,别忘了加上null字符。

    实验4:

    sscanf("AAAaaaBBB","%[^a-z]",str); ---------str的值为 "AAA!!!!!!"

    对 于所有字符,只要不是小写字母,都满足"^a-z"正则表达式,符号^表示逻辑非。前3个字符都不是小写字符,所以将其拷贝给str,但最后3个字符也不 是小写字母,为什么不拷贝给str呢?这是因为当碰到不满足条件的字符后,sscanf就会停止执行,不再扫描之后的字符。

    实验5:

    sscanf("AAAaaaBBB","%[A-Z]%[a-z]",str); ---------段错误

    这 个实验的本意是:先把大写字母拷贝给str,然后把小写字母拷贝给str,但很不幸,程序运行的时候会发生段错误,因为当sscanf扫描到字符a时,违 反了条件"%[A-Z]",sscanf就停止执行,不再扫描之后的字符,所以第二个条件也就没有任何意义,这个实验说明:不能使用%号两次或两次以上

    实验6:

    sscanf("AAAaaaBBB","%*[A-Z]%[a-z]",str); ---------str的值为 "aaa!!!!!!"

    这 个实验出现了一个新的符号:%*,与%相反,%*表示过滤满足条件的字符,在这个实验中,%*[A-Z]过滤了所有大写字母,然后再使用%[a-z]把之 后的小写字母拷贝给str。如果只有%*,没有%的话,sscanf不会拷贝任何字符到str,这时sscanf的作用仅仅是过滤字符串。

    实验7:

    sscanf("AAAaaaBBB","%[a-z]",str); ---------str的值为 "!!!!!!!!!!"

    做 完前面几个实验后,我们都知道sscanf拷贝完成后,还会在str的后面加上一个null字符,但如果没有一个字符满足条件,sscanf不会在str 的后面加null字符,str的值依然是10个惊叹号。这个实验也说明了,如果不使用%*过滤掉前面不需要的字符,你永远别想取得中间的字符。

    实验8:

    sscanf("AAAaaaBC=","%*[A-Z]%*[a-z]%[^a-z=]",str); ---------str的值为 "BC!!!!!!!"

    这是一个综合实验,但这个实验的目的不是帮我们复习前面所学的知识,而是展示两个值得注意的地方:

    注意1:%只能使用一次,但%*可以使用多次,比如在这个实验里面,先用%*[A-Z]过滤大写字母,然后用%*[a-z]过滤小写字母。

    注意2:^后面可以带多个条件,且这些条件都受^的作用,比如^a-z=表示^a-z且^=(既不是小写字母,也不是等于号)。

    实验9:

    int k;

    sscanf("AAA123BBB456", "%*[^0-9]%i", &k); ---------k的值为123

    首先,%*[^0-9]过滤前面非数字的字符,然后用%i把数字字符转换成int型的整数,拷贝到变量k,注意参数必须使用k的地址。

    ==================================================================

    这里有些sscanf()的一些使用说明,都是从论坛,Blog里整理出来的。供大家使用。
       通过学习和使用个人认为,在字符串格式不是很复杂,但是也并不简单的时候用这个函数比较合适,这个尺度就要靠自己把握了,字符串不是很复杂,但自己写个处理的函数比较麻烦,效率也不高,就用这个函数,如果字符串很复杂,那就用正则表达式吧。
    不多说了,看看下面这些介绍和列子吧!
    名称:sscanf() - 从一个字符串中读进与指定格式相符的数据.
    函数原型:
    Int  sscanf( string str, string fmt, mixed var1, mixed var2 ... );
    int  scanf( const char *format [,argument]... );
    说明:
    sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
    其中的format可以是一个或多个 {%[*] [width] [{h | l | I64 | L}]type | ' ' | ' ' | ' ' | 非%符号}
    支持集合操作:
         %[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
         %[aB'] 匹配a、B、'中一员,贪婪性
         %[^a] 匹配非a的任意字符,贪婪性
    例子:
    1. 常见用法。
        char buf[512] = {0};
        sscanf("123456 ", "%s", buf);
        printf("%s ", buf);
    结果为:123456
    2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。
        sscanf("123456 ", "%4s", buf);
        printf("%s ", buf);
    结果为:1234
    3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。
        sscanf("123456 abcdedf", "%[^ ]", buf);
        printf("%s ", buf);
    结果为:123456
     
    4.  取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
        sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
        printf("%s ", buf);
    结果为:123456abcdedf
     
    5.  取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。
        sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);
        printf("%s ", buf);
    结果为:123456abcdedf
    6、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
        sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
        printf("%s ", buf);
    结果为:12DDWDFF
     
    7、给定一个字符串““hello, world”,仅保留world。(注意:“,”之后有一空格)
        sscanf(“hello, world”,  "%*s%s",  buf);   
        printf("%s ", buf);
    结果为:world
    %*s表示第一个匹配到的%s被过滤掉,即hello被过滤了
    如果没有空格则结果为NULL。
    8、
     char *s="1try234delete5"  
    则: 
    sscanf(s, "1%[^2]234%[^5]", s1, s2); 
    scanf的format中出现的非转换字符(%之前或转换字符之后的字符),即此例中的1234用来跳过输入中的相应字符; 
    ‘[]’的含义与正则表达式中相同,表示匹配其中出现的字符序列;^表示相反。使用[ ]时接收输入的变量必须是有足够存储空间的char、signed char、unsigned char数组。记住[也是转换字符,所以没有s了。
    8、分割以某字符标记的字符串。
     char test[]="222,333,444,,,555,666"; 
     char s1[4],s2[4],s3[4],s4[4],s5[4],s6[4],s7[4]; 
     sscanf(test,"%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]",s1,s2,s3,s4,s5,s6,s7); 
     printf("sssa1=%s",s1); 
     printf("sssa2=%s",s2); 
     printf("sssa3=%s",s3); 
     printf("sssa4=%s",s4); 
     printf("sssa5=%s",s5); 
     printf("sssa6=%s",s6); 
     printf("sssa7=%s",s7); 
    9、一个提取用户个人资料中邮件地址的例子 
    #include<cstdlib>
    #include<cstdio>
    using namespace std;
    int main()
    {
        char a[20]={0};
        char b[20]={0};
        //假设email地址信息以';'结束 
        sscanf("email:jimmywhr@gmail.com;","%*[^:]:%[^;]",a);
        //假设email地址信息没有特定的结束标志 
        sscanf("email:jimmywhr@gmail.com","%*[^:]:%s",b);
        printf("%s ",a);
        printf("%s ",b);
        system("pause");
        return 0;
    }
      关键是"%*[^:]:%[^;]"和"%*[^:]:%s"这两个参数的问题 
      %*[^:]    表示满足"[]"里的条件将被过滤掉,不会向目标参数中写入值。这里的意思是在
                第一个':'之前的字符会在写入时过滤掉,'^'是表示否定的意思,整个参数翻译
                成白话就是:将在遇到第一个':'之前的(不为':'的)字符全部过滤掉。 
      :         自然就是跳过':'的意思。
      %[^;]     拷贝字符直到遇到';'。
    一下摘自:http://blog.csdn.net/lbird/archive/2007/08/03/1724429.aspx
    %[ ] 的用法:%[ ]表示要读入一个字符集合, 如果[ 后面第一个字符是”^”,则表示反意思。
                         [ ]内的字符串可以是1或更多字符组成。空字符集(%[])是违反规定的,可
                         导致不可预知的结果。%[^]也是违反规定的。
             
    %[a-z] 读取在 a-z 之间的字符串,如果不在此之前则停止,如
                  char s[]="hello, my friend” ;         // 注意: ,逗号在不 a-z之间
                  sscanf( s, “%[a-z]”, string ) ; // string=hello

    %[^a-z] 读取不在 a-z 之间的字符串,如果碰到a-z之间的字符则停止,如
                  char s[]="HELLOkitty” ;         // 注意: ,逗号在不 a-z之间
                  sscanf( s, “%[^a-z]”, string ) ; // string=HELLO

    %*[^=]    前面带 * 号表示不保存变量。跳过符合条件的字符串。
                  char s[]="notepad=1.0.0.1001" ;
           char szfilename [32] = "" ;
           int i = sscanf( s, "%*[^=]", szfilename ) ; // szfilename=NULL,因为没保存
     int i = sscanf( s, "%*[^=]=%s", szfilename ) ; // szfilename=1.0.0.1001
    %40c      读取40个字符
           The run-time
     library does not automatically append a null terminator
     to the string, nor does reading 40 characters
     automatically terminate the scanf() function. Because the
     library uses buffered input, you must press the ENTER key
     to terminate the string scan. If you press the ENTER before
     the scanf() reads 40 characters, it is displayed normally,
     and the library continues to prompt for additional input
     until it reads 40 characters

    %[^=]     读取字符串直到碰到’=’号,’^’后面可以带更多字符,如:
                  char s[]="notepad=1.0.0.1001" ;
           char szfilename [32] = "" ;
           int i = sscanf( s, "%[^=]", szfilename ) ; // szfilename=notepad     
           如果参数格式是:%[^=:] ,那么也可以从 notepad:1.0.0.1001读取notepad
                 
    使用例子:
     char s[]="notepad=1.0.0.1001" ;
     char szname [32] = "" ;
     char szver [32] = “” ;
    sscanf( s, "%[^=]=%s", szname , szver ) ; // szname=notepad, szver=1.0.0.1001
    总结:%[]有很大的功能,但是并不是很常用到,主要因为:
    1、许多系统的 scanf 函数都有漏洞. (典型的就是 TC 在输入浮点型时有时会出错).
    2、用法复杂, 容易出错.
    3、编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率.
    个人觉得第3点最致命,越复杂的功能往往执行效率越低下。而一些简单的字符串分析我们可以自已处理。

    以前只是简单是使用sscanf,却没发现其还有如此强大的功能
     char str0[100],str1[100],str2[100],str3[100];

     sscanf("abcde abc 123 aaa","%s %s %s %s",str0,str1,str2,str3);
     结果:str0="abcde"   str1="abc"  str2 = "123" str3="aaa"

     sscanf("abcde abc 123 aaa","abc%s %s %*d %s",str0,str1,str3);
     结果:str0="abcde"   str1="abc"  str3="aaa"

     sscanf("abc123 efg456","%4s",str0);
     结果:str0="abc1"   

     sscanf("abc123 efg456a4","%[a-z 1-5]",str0);
     结果:str0="abc123 efg45"   

    sscanf("abc123 efg456a4","%[a-z1-5]",str0);
     结果:str0="abc123" 

     sscanf("ABCTabcZ123 efg456","%[A-P]",str0);
     结果:str0="ABC"   

     sscanf("abc 12345","%[^ ]",str0);
     结果:str0="abc"   

     sscanf("abc 12345","%[^4]",str0);
     结果:str0="abc 123"   

     sscanf("fdaBs 52aB1asdf","%[^4-0]",str0);
     结果:str0="fdaBs 5"   

     sscanf("abc 12345","%[^ ]%[^3]",str0,str1);
     结果:str0="abc"    str1="12"

     sscanf("abc301abc2345","%*[^9-0]%s",str0); 
     结果:str0="301abc2345"   
     sscanf("bca@123efg4@5abc","%*[^@]@%[^@]",str0);
     结果:str0="123efg4"   

  • 相关阅读:
    Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
    无向图求点割集的算法
    hdu 2121无根最小树形图要建一个虚拟节点
    hdu 1576扩展欧几里得算法
    欧几里德算法的扩展-求解不定方程
    hdu 3072 强连通+缩点+最小树形图思想
    1352 集合计数 扩展欧几里德算法
    1247 可能的路径 逆向思维
    Atcoder B
    C. Timofey and a tree 观察题 + dfs模拟
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/3430057.html
Copyright © 2011-2022 走看看