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

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

验证代码如下

#if 0
1,sscanf():从一个字符串中读进与指定格式相符的数据.
2,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
3,关于正则表达式:
(1)%[..],当字符属于方括号里表达式表示的字符集时继续读取,否则停止.方括号里的和正则表达式差不多,^是"排除..."的意思
(2)%*[..],直接跳过方括号里的字符集并继续读取
#endif #include <iostream>
using namespace std; int main()
{
char str[10]; // 这个实验很简单,把源字符串"123456"拷贝到str的前6个字符,并且把str的第7个字符设为null字符,也就是\0
for (int i = 0; i < 10; i++) str[i] = '!';
cout<<str<<endl;
sscanf("123456", "%s", str); // str的值为 "123456\0!!!"
cout<<str<<endl; // 看到没有,正则表达式的百分号后面多了一个3,这告诉sscanf只拷贝3个字符给str,然后把第4个字符设为null字符。
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("123456", "%3s", str); // str的值为 "123\0!!!!!!"
cout<<str<<endl; // 从这个实验开始我们会使用正则表达式,括号里面的a-z就是一个正则表达式,它可以表示从a到z的任意字符,
// 在继续讨论之前,我们先来看看百分号表示什么意思,%表示选择,%后面的是条件,比如实验1的"%s",s是一个条件,表示任意字符,"%s"的意思是:-
// -只要输入的东西是一个字符,就把它拷贝给str。实验2的"%3s"又多了一个条件:只拷贝3个字符。实验3的“%[a-z]”的条件稍微严格一些,输入的-
// -东西不但是字符,还得是一个小写字母的字符,所以实验3只拷贝了小写字母"aaa"给str,别忘了加上null字符。
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("aaaAAA", "%[a-z]", str); // str的值为 "aaa\0!!!!!!"
cout<<str<<endl; // 对于所有字符,只要不是小写字母,都满足"^a-z"正则表达式,符号^表示逻辑非。前3个字符都不是小写字符,所以将其拷贝给str,但最后3个字符-
// -也不是小写字母,为什么不拷贝给str呢?这是因为当碰到不满足条件的字符后,sscanf就会停止执行,不再扫描之后的字符。
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("AAAaaaBBB", "%[^a-z]", str); // str的值为 "AAA\0!!!!!!"
cout<<str<<endl; /*
// 这个实验的本意是:先把大写字母拷贝给str,然后把小写字母拷贝给str,但很不幸,程序运行的时候会发生段错误,因为当sscanf扫描到字符a时,-
// -违反了条件"%[A-Z]",sscanf就停止执行,不再扫描之后的字符,所以第二个条件也就没有任何意义,这个实验说明:不能使用%号两次或两次以上
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("AAAaaaBBB", "%[A-Z]%[a-z]", str); // 段错误
cout<<str<<endl;
*/ // 这个实验出现了一个新的符号:%*,与%相反,%*表示过滤满足条件的字符,在这个实验中,%*[A-Z]过滤了所有大写字母,然后再使用%[a-z]把之后-
// -的小写字母拷贝给str。如果只有%*,没有%的话,sscanf不会拷贝任何字符到str,这时sscanf的作用仅仅是过滤字符串。
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("AAAaaaBBB", "%*[A-Z]%[a-z]", str); // str的值为 "aaa\0!!!!!!"
cout<<str<<endl; // 做完前面几个实验后,我们都知道sscanf拷贝完成后,还会在str的后面加上一个null字符,但如果没有一个字符满足条件,sscanf不会在str 的后面-
// -加null字符,str的值依然是10个惊叹号。这个实验也说明了,如果不使用%*过滤掉前面不需要的字符,你永远别想取得中间的字符。
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("AAAaaaBBB", "%[a-z]", str); // str的值为 "!!!!!!!!!!"
cout<<str<<endl; // 这是一个综合实验,但这个实验的目的不是帮我们复习前面所学的知识,而是展示两个值得注意的地方:
// 注意1:%只能使用一次,但%*可以使用多次,比如在这个实验里面,先用%*[A-Z]过滤大写字母,然后用%*[a-z]过滤小写字母。
// 注意2:^后面可以带多个条件,且这些条件都受^的作用,比如^a-z=表示^a-z且^=(既不是小写字母,也不是等于号)。
for (int i = 0; i < 10; i++) str[i] = '!';
sscanf("AAAaaaBC=", "%*[A-Z]%*[a-z]%[^a-z=]", str); // str的值为 "BC\0!!!!!!!"
cout<<str<<endl; // 首先,%*[^0-9]过滤前面非数字的字符,然后用%i把数字字符转换成int型的整数,拷贝到变量k,注意参数必须使用k的地址。 cout<<str<<endl;
for (int i = 0; i < 10; i++) str[i] = '!';
int k;
sscanf("AAA123BBB456", "%*[A-Z]%i", &k); // k的值为123
cout<<k<<endl;
return 0;
}

参考:https://www.iteye.com/blog/kmplayer-556293

【C/C++】sscanf函数和正则表达式的更多相关文章

  1. sscanf函数和正则表达式

    看了几篇介绍sscanf函数,真是发现自己好多东西没理解透,详细介绍使用在sscanf中使用正则表达式. 第一篇: 此文所有的实验都是基于下面的程序: char str[10]; for (int i ...

  2. c语言 sscanf()函数

    sscanf()函数用于从字符串中读取指定格式的数据,其原型如下:    int sscanf (char *str, char * format [, argument, ...]); [参数]参数 ...

  3. sscanf函数——强大的C语言库函数

    这个函数真的很强大,这篇随笔也将一直更新一些总结,直到涵盖大多数应用: eg1: 今天公司项目中从云端获取了一段字符串---"+CBC: 0,90,4090" 我想获取其中的数字0 ...

  4. [转载]sscanf函数

    来源:http://c.biancheng.net/cpp/html/296.html 头文件:#include <stdio.h> sscanf()函数用于从字符串中读取指定格式的数据, ...

  5. sscanf()函数的使用及其实例

    资料引自: 传送门 sscanf函数原型: Int sscanf( const char * src, const char * format, ...); int scanf( const char ...

  6. sscanf函数

    sscanf函数用法举例 #include <stdio.h> #include <string.h> #define N 512 int main() { char buf[ ...

  7. C语言sprintf与sscanf函数[总结]

    sprintf函数 sprintf函数原型为 int sprintf(char *str, const char *format, ...).作用是格式化字符串,具体功能如下所示: (1)将数字变量转 ...

  8. sscanf 函数

    sscanf 函数: 从一个字符串中读进与指定格式相符的数据. 头文件: #include<stdio.h> 返回值:  sscanf("1 2 3","%d ...

  9. php sscanf() 函数使用

    定义和用法 sscanf() 函数根据指定的格式解析来自一个字符串的输入. 如果只向该函数传递两个参数,数据将以数组的形式返回.否则,如果传递了额外的参数,那么被解析的数据会存储在这些参数中.如果区分 ...

  10. 关于sscanf函数的各种详细用法

    看书的时候碰到sscanf函数,就上网查了很多资料,并加以自己的整理,希望对大家有所帮助. (因为参考的博客太多太散,就不一一注明,望大神们见谅) sscanf()  :从一个字符串中读进与指定格式相 ...

随机推荐

  1. Linux:LVM磁盘扩容实战

    1.列出分区表 命令:fdisk -l 查看到目前挂载了 vda1.vda2.vda3,并且查看到还有vdb 100G没有挂载,以及现在的LV大小仅为29G root@JumpServer-DB-T0 ...

  2. Ubuntu图形界面root登录“sorry, that didn't work please

    https://blog.51cto.com/u_14757092/2484490 ssh登录主机执行下vim /etc/pam.d/gdm-autologin 注释行 "auth requ ...

  3. MyBatis 的缓存处理

    作为常见的 ORM 框架,在使用 MyBatis 的过程中可以针对相关的查询进行缓存处理以提高查询的性能.本文将简要介绍一下 MyBatis 中默认的一级缓存和二级缓存,以及自定义缓存的处理 MyBa ...

  4. Spring Eureka 源码解析

    本文将简要分析一下关于 Spring Eureka 相关的一些必要的源代码,对应的版本:Spring Cloud 2021.0.1 @EnableEurekaServer 注解 @EnableEure ...

  5. Java通过SSH连接路由器,输入命令并读取响应

    最近需要读取和修改华为路由器的配置,使用Java语言开发,通过SSH连接,输入命令并读取响应. 1.添加mwiede/jsch依赖 如果使用Maven,可以在pom.xml文件中添加以下依赖: < ...

  6. 如何构建一个 NodeJS 影院微服务并使用 Docker 部署

    如何构建一个 NodeJS 影院微服务并使用 Docker 部署 前言 如何构建一个 NodeJS 影院微服务并使用 Docker 部署.在这个系列中,将构建一个 NodeJS 微服务,并使用 Doc ...

  7. 华为云FusionInsight MRS在金融行业存算分离的实践

    摘要:华为云FusionInsight MRS的大数据存算分离解决方案,实现资源价值最大化,存储与计算资源全面云化.灵活配置.弹性伸缩,降本增效. 在大数据.云计算.5G.AI等技术日新月异,数字经济 ...

  8. 华为云PB级数据库GaussDB(for Redis)介绍第四期:高斯 Geo的介绍与应用

    摘要:高斯Redis的大规模地理位置信息存储的解决方案. 1.背景 LBS(Location Based Service,基于位置的服务)有非常广泛的应用场景,最常见的应用就是POI(Point of ...

  9. 带你了解数仓安全测试的TLS协议

    摘要:SSL/TLS协议是业界常用的加密通信协议,通过该协议可以完成通信双方身份认证,会话密钥协商,通信内容加密和完整性保护. 本文分享自华为云社区<GaussDB(DWS)安全测试之TLS协议 ...

  10. 被灵魂问倒:这个BUG为什么没测出来?

    摘要:为什么没测出来!测试怎么测得?到底会不会测?这对测试来说是灵魂拷问级别不好回答的问题了. 本文分享自华为云社区<被问:这个BUG为什么没测出来?该如何回答>,作者: 曲鸟. 一.前言 ...