• sscanf函数和正则表达式


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

    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的地址。 

    #if 0
    1,sscanf():从一个字符串中读进与指定格式相符的数据.
    2,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
    3,关于正则表达式:
        (1)%[..],当字符属于方括号里表达式表示的字符集时继续读取,否则停止.方括号里的和正则表达式差不多,^是"排除..."的意思
        (2)%*[..],直接跳过方括号里的字符集并继续读取
    #endif
    
    #include <iostream>
    using namespace std;
    
    int main()
    {
        char str[10];
        for (int i = 0; i < 10; i++) str[i] = '!';
        cout<<str<<endl;
        sscanf("123456","%s",str);//---------str的值为 "123456!!!"
        //这个实验很简单,把源字符串"123456"拷贝到str的前6个字符,并且把str的第7个字符设为null字符,也就是
        cout<<str<<endl;
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        sscanf("123456","%3s",str); //---------str的值为 "123!!!!!!"
        //看到没有,正则表达式的百分号后面多了一个3,这告诉sscanf只拷贝3个字符给str,然后把第4个字符设为null字符。
        cout<<str<<endl;
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        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字符。
        cout<<str<<endl;
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        sscanf("AAAaaaBBB","%[^a-z]",str);// ---------str的值为 "AAA!!!!!!"
        //对于所有字符,只要不是小写字母,都满足"^a-z"正则表达式,符号^表示逻辑非。前3个字符都不是小写字符,所以将其拷贝给str,但最后3个字符也不是小写字母,为什么不拷贝给str呢?这是因为当碰到不满足条件的字符后,sscanf就会停止执行,不再扫描之后的字符。
        cout<<str<<endl;
    
        /*
        for (int i = 0; i < 10; i++) str[i] = '!';
        sscanf("AAAaaaBBB","%[A-Z]%[a-z]",str);// ---------段错误
        //这个实验的本意是:先把大写字母拷贝给str,然后把小写字母拷贝给str,但很不幸,程序运行的时候会发生段错误,因为当sscanf扫描到字符a时,违反了条件"%[A-Z]",sscanf就停止执行,不再扫描之后的字符,所以第二个条件也就没有任何意义,这个实验说明:不能使用%号两次或两次以上
        cout<<str<<endl;
        */
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        sscanf("AAAaaaBBB","%*[A-Z]%[a-z]",str); //---------str的值为 "aaa!!!!!!"
        //这个实验出现了一个新的符号:%*,与%相反,%*表示过滤满足条件的字符,在这个实验中,%*[A-Z]过滤了所有大写字母,然后再使用%[a-z]把之后的小写字母拷贝给str。如果只有%*,没有%的话,sscanf不会拷贝任何字符到str,这时sscanf的作用仅仅是过滤字符串。
        cout<<str<<endl;
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        sscanf("AAAaaaBBB","%[a-z]",str);// ---------str的值为 "!!!!!!!!!!"
        //做完前面几个实验后,我们都知道sscanf拷贝完成后,还会在str的后面加上一个null字符,但如果没有一个字符满足条件,sscanf不会在str 的后面加null字符,str的值依然是10个惊叹号。这个实验也说明了,如果不使用%*过滤掉前面不需要的字符,你永远别想取得中间的字符。
        cout<<str<<endl;
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        sscanf("AAAaaaBC=","%*[A-Z]%*[a-z]%[^a-z=]",str); //---------str的值为 "BC!!!!!!!"
        //这是一个综合实验,但这个实验的目的不是帮我们复习前面所学的知识,而是展示两个值得注意的地方:
        //注意1:%只能使用一次,但%*可以使用多次,比如在这个实验里面,先用%*[A-Z]过滤大写字母,然后用%*[a-z]过滤小写字母。
        // 注意2:^后面可以带多个条件,且这些条件都受^的作用,比如^a-z=表示^a-z且^=(既不是小写字母,也不是等于号)。
        cout<<str<<endl;
    
        for (int i = 0; i < 10; i++) str[i] = '!';
        int k;
        sscanf("AAA123BBB456", "%*[A-Z]%i", &k); //---------k的值为123
        //首先,%*[^0-9]过滤前面非数字的字符,然后用%i把数字字符转换成int型的整数,拷贝到变量k,注意参数必须使用k的地址。    cout<<str<<endl;
        cout<<k<<endl;
        return 0;
    }
    /*****************************************************
    ** Name         : sscanf.c 
    ** Author       : gzshun
    ** Version      : 1.0
    ** Date         : 2011-12
    ** Description  : sscanf function
    ******************************************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static void sscanf_test(void);
    
    static void sscanf_test(void)
    {
        int ret;
        char *string;
        int  digit;
        char buf1[255];
        char buf2[255];
        char buf3[255];
        char buf4[255];
    
        /*1.最简单的用法*/
        string = "china beijing 123";
        ret = sscanf(string, "%s %s %d", buf1, buf2, &digit);
        printf("1.string=%s
    ", string);
        printf("1.ret=%d, buf1=%s, buf2=%s, digit=%d
    
    ", ret, buf1, buf2, digit);
        /*
        **执行结果:
        **1.ret=3, buf1=china, buf2=beijing, digit=123
        **可以看出,sscanf的返回值是读取的参数个数
        */
    
        /*2.取指定长度的字符串*/
        string = "123456789";
        sscanf(string, "%5s", buf1);
        printf("2.string=%s
    ", string);
        printf("2.buf1=%s
    
    ", buf1);
        /*
        **执行结果:
        **2.buf1=12345
        */
    
        /*3.取到指定字符为止的字符串*/
        string = "123/456";
        sscanf(string, "%[^/]", buf1);
        printf("3.string=%s
    ", string);
        printf("3.buf1=%s
    
    ", buf1);
        /*
        **执行结果:
        **3.buf1=123
        */
    
        /*4.取到指定字符集为止的字符串*/
        string = "123abcABC";
        sscanf(string, "%[^A-Z]", buf1);
        printf("4.string=%s
    ", string);
        printf("4.buf1=%s
    
    ", buf1);
        /*
        **执行结果:
        **4.buf1=123abc
        */
    
        /*5.取仅包含指定字符集的字符串*/
        string = "0123abcABC";
        sscanf(string, "%[0-9]%[a-z]%[A-Z]", buf1, buf2, buf3);
        printf("5.string=%s
    ", string);
        printf("5.buf1=%s, buf2=%s, buf3=%s
    
    ", buf1, buf2, buf3);
        /*
        **执行结果:
        **5.buf1=123, buf2=abc, buf3=ABC
        */
    
        /*6.获取指定字符中间的字符串*/
        string = "ios<android>wp7";
        sscanf(string, "%*[^<]<%[^>]", buf1);
        printf("6.string=%s
    ", string);
        printf("6.buf1=%s
    
    ", buf1);
        /*
        **执行结果:
        **6.buf1=android
        */
    
        /*7.指定要跳过的字符串*/
        string = "iosVSandroid";
        sscanf(string, "%[a-z]VS%[a-z]", buf1, buf2);
        printf("7.string=%s
    ", string);
        printf("7.buf1=%s, buf2=%s
    
    ", buf1, buf2);
        /*
        **执行结果:
        **7.buf1=ios, buf2=android
        */
    
        /*8.分割以某字符隔开的字符串*/
        string = "android-iphone-wp7";
        /*
        **字符串取道'-'为止,后面还需要跟着分隔符'-',
        **起到过滤作用,有点类似于第7点
        */
        sscanf(string, "%[^-]-%[^-]-%[^-]", buf1, buf2, buf3);
        printf("8.string=%s
    ", string);
        printf("8.buf1=%s, buf2=%s, buf3=%s
    
    ", buf1, buf2, buf3);
        /*
        **执行结果:
        **8.buf1=android, buf2=iphone, buf3=wp7
        */
    
        /*9.提取邮箱地址*/
        string = "Email:beijing@sina.com.cn";
        sscanf(string, "%[^:]:%[^@]@%[^.].%s", buf1, buf2, buf3, buf4);
        printf("9.string=%s
    ", string);
        printf("9.buf1=%s, buf2=%s, buf3=%s, buf4=%s
    
    ", buf1, buf2, buf3, buf4);
        /*
        **执行结果:
        **9.buf1=Email, buf2=beijing, buf3=sina, buf4=com.cn
        */
    
        /*10.过滤掉不想截取或不需要的字符串--补充,
        **在%号后面加一*号,代表过滤这个字符串,不读取
        */
        string = "android iphone wp7";
        sscanf(string, "%s %*s %s", buf1, buf2);
        printf("10.string=%s
    ", string);
        printf("10.buf1=%s, buf2=%s
    
    ", buf1, buf2);
        /*
        **执行结果:
        **10.android wp7
        */
    }
    
    int main(int argc, char **argv)
    {
        sscanf_test();
        
        return 0;
    }
    
    /*
    **测试程序
    **环境:
    **Linux ubuntu 2.6.32-24-generic-pae #39-Ubuntu SMP Wed Jul 28 07:39:26 UTC 2010 i686 GNU/Linux
    **gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
    **
    gzshun@ubuntu:~/c/sscanf$ gcc sscanf.c -o sscanf
    gzshun@ubuntu:~/c/sscanf$ ./sscanf
    1.string=china beijing 123
    1.ret=3, buf1=china, buf2=beijing, digit=123
    
    2.string=123456789
    2.buf1=12345
    
    3.string=123/456
    3.buf1=123
    
    4.string=123abcABC
    4.buf1=123abc
    
    5.string=0123abcABC
    5.buf1=0123, buf2=abc, buf3=ABC
    
    6.string=ios<android>wp7
    6.buf1=android
    
    7.string=iosVSandroid
    7.buf1=ios, buf2=android
    
    8.string=android-iphone-wp7
    8.buf1=android, buf2=iphone, buf3=wp7
    
    9.string=Email:beijing@sina.com.cn
    9.buf1=Email, buf2=beijing, buf3=sina, buf4=com.cn
    
    10.string=android iphone wp7
    10.buf1=android, buf2=wp7
    */

    代码来源:

    http://kmplayer.iteye.com/blog/556293 

    http://blog.csdn.net/gzshun/article/details/7081736

  • 相关阅读:
    Android 去除最上面应用名称及图标
    Android 仿QQ消息界面
    多线程断点续传及下载
    android 断点下载---XUtils
    Android判断网路是否畅通加权限
    Android_按两次返回键退出程序和长按返回键退出程序
    Android JPush(极光推送)的使用教程
    使用VS2013自带的PreEmptive Dotfuscator and Analytis来混淆C#代码
    Entity Framework 6连接Oracle、Postgresql、SQLite、LocalDB数据库字符串详解
    Fluent Nhibernate 数据库配置
  • 原文地址:https://www.cnblogs.com/lipching/p/3874840.html
Copyright © 2020-2023  润新知