Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1438206
  • 博文数量: 704
  • 博客积分: 10140
  • 博客等级: 上将
  • 技术积分: 6230
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-15 20:41
文章分类

全部博文(704)

文章存档

2013年(1)

2012年(16)

2011年(536)

2010年(151)

分类:

2011-11-07 22:00:05

原文地址:sscanf函数和正则表达式 作者:digdeep126

转自:http://kmplayer.javaeye.com/blog/556293

此文所有的实验都是基于下面的程序:
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\0!!!"
这个实验很简单,把源字符串"123456"拷贝到str的前6个字符,并且把str的第7个字符设为null字符,也就是\0

实验2:
sscanf("123456", "%3s",  str); ---------str的值为 "123\0!!!!!!"
看到没有,正则表达式的百分号后面多了一个3,这告诉sscanf只拷贝3个字符给str,然后把第4个字符设为null字符。

实验3:
sscanf("aaaAAA", "%[a-z]", str); ---------str的值为 "aaa\0!!!!!!"
从这个实验开始我们会使用正则表达式,括号里面的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\0!!!!!!"
对于所有字符,只要不是小写字母,都满足"^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\0!!!!!!"
这个实验出现了一个新的符号:%*,与%相反,%*表示过滤满足条件的字符,在这个实验中,%*[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\0!!!!!!!"
这是一个综合实验,但这个实验的目的不是帮我们复习前面所学的知识,而是展示两个值得注意的地方:

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

仍段代码下来:

  1. #if 0
  2. 1,sscanf():从一个字符串中读进与指定格式相符的数据.
  3. 2,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
  4. 3,关于正则表达式:
  5.     (1)%[..],当字符属于方括号里表达式表示的字符集时继续读取,否则停止.方括号里的和正则表达式差不多,
  6.        ^"排除..."的意思
  7.     (2)%*[..],直接跳过方括号里的字符集并继续读取
  8. #endif

  9. #include <iostream>
  10. using namespace std;

  11. int main()
  12. {
  13.     char str[10];
  14.     for (int i = 0; i < 10; i++) 
  15.        str[i] = '!';
  16.     cout <str <endl;
  17.     sscanf("123456","%s"str);//---------str的值为 "123456\0!!!"
  18.     /这个实验很简单,把源字符串"123456"拷贝到str的前6个字符,
  19.     /并且把str的第7个字符设为null字符,也就是\0
  20.     cout <str <endl;

  21.     for (int i = 0; i < 10; i++) 
  22.        str[i] = '!';
  23.     sscanf("123456""%3s"str); //---------str的值为 "123\0!!!!!!"
  24.     /看到没有,正则表达式的百分号后面多了一个3,这告诉sscanf只拷贝3个字符给str,
        /然后把第4个字符设为null字符。
  25.     cout <str <endl;

  26.     for (int i = 0; i < 10; i++) 
  27.        str[i] = '!';
  28.     sscanf("aaaAAA""%[a-z]"str)// ---------str的值为 "aaa\0!!!!!!"
  29.     /*从这个实验开始我们会使用正则表达式,括号里面的a-z就是一个正则表达式,它可以表示从a到z的任意字符,
  30.       在继续讨论之前,我们先来看看百分号表示什么意思,%表示选择,%后面的是条件,比如实验1的"%s"
  31.       s是一个  条件,表示任意字符,"%s"的意思是:只要输入的东西是一个字符,就把它拷贝给str。
  32.       实验2的"%3s"又多了一个条件:只拷贝3个字符。实验3的“%[a-z]”的条件稍微严格一些,输入的东西不但是字符,       还得是一个小写字母的字符,所以实验3只拷贝了小写字母"aaa"给str,别忘了加上null字符。
  33.     */
  34.     cout <str <endl;

  35.     for (int i = 0; i < 10; i++) 
  36.        str[i] = '!';
  37.     sscanf("AAAaaaBBB""%[^a-z]"str)// ---------str的值为 "AAA\0!!!!!!"
  38.     /*对于所有字符,只要不是小写字母,都满足"^a-z"正则表达式,符号^表示逻辑非。
  39.       前3个字符都不是小写字符,所以将其拷贝给str,但最后3个字符也不是小写字母,为什么不拷贝给str呢?
  40.       这是因为当碰到不满足条件的字符后,sscanf就会停止执行,不再扫描之后的字符。
  41.     */
  42.     cout <str <endl;

  43.     /*
  44.     for (int i = 0; i < 10; i++) 
  45.        str[i] = '!';
  46.     sscanf("AAAaaaBBB""%[A-Z]%[a-z]"str)// ---------段错误
  47.     /*这个实验的本意是:先把大写字母拷贝给str,然后把小写字母拷贝给str,但很不幸,
  48.       程序运行的时候会发生段错误,因为当sscanf扫描到字符a时,违反了条件"%[A-Z]",sscanf就停止执行,
  49.       不再扫描之后的字符,所以第二个条件也就没有任何意义,这个实验说明:不能使用%号两次或两次以上
  50.       cout <str <endl;
  51.     */

  52.     for (int i = 0; i < 10; i++) 
  53.        str[i] = '!';
  54.     sscanf("AAAaaaBBB""%*[A-Z]%[a-z]"str); //---------str的值为 "aaa\0!!!!!!"
  55.     /这个实验出现了一个新的符号:%*,与%相反,%*表示过滤满足条件的字符,在这个实验中,
  56.     /%*[A-Z]过滤了所有大写字母,然后再使用%[a-z]把之后的小写字母拷贝给str。如果只有%*,没有%的话,
  57.     /sscanf不会拷贝任何字符到str,这时sscanf的作用仅仅是过滤字符串。
  58.     cout <str <endl;

  59.     for (int i = 0; i < 10; i++) 
  60.       str[i] = '!';
  61.     sscanf("AAAaaaBBB""%[a-z]"str)// ---------str的值为 "!!!!!!!!!!"
  62.     /做完前面几个实验后,我们都知道sscanf拷贝完成后,还会在str的后面加上一个null字符,
  63.     /但如果没有一个字符满足条件,sscanf不会在str 的后面加null字符,str的值依然是10个惊叹号。
  64.     /这个实验也说明了,如果不使用%*过滤掉前面不需要的字符,你永远别想取得中间的字符。
  65.     cout <str <endl;

  66.     for (int i = 0; i < 10; i++) 
  67.        str[i] = '!';
  68.     sscanf("AAAaaaBC=""%*[A-Z]%*[a-z]%[^a-z=]"str); //---------str的值为 "BC\0!!!!!!!"
  69.     /这是一个综合实验,但这个实验的目的不是帮我们复习前面所学的知识,而是展示两个值得注意的地方:
  70.     /注意1:%只能使用一次,但%*可以使用多次,比如在这个实验里面,先用%*[A-Z]过滤大写字母,
  71.     /然后用%*[a-z]过滤小写字母。
  72.     // 注意2:^后面可以带多个条件,且这些条件都受^的作用,比如^a-z=表示^a-z且^=(既不是小写字母,
  73.     // 也不是等于号)
  74.     cout <str <endl;

  75.     for (int i = 0; i < 10; i++) 
  76.        str[i] = '!';
  77.     int k;
  78.     sscanf("AAA123BBB456", "%*[A-Z]%i", &k); //---------k的值为123
  79.     /首先,%*[^0-9]过滤前面非数字的字符,然后用%i把数字字符转换成int型的整数,拷贝到变量k,
  80.     /注意参数必须使用k的地址。 cout<<str<<endl;
  81.     cout <<endl;

  82.     return 0;
  83. }

 

阅读(357) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~