在看这篇文章之前建议你先了解一下什么是正则表达式,具体不重复了,google一下能出一大堆,不过这篇文章比较好,贴个urlhttp://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm,作者说30分钟能看完的不是地球人,但是我15分钟就看完了还记住了90%以上,好吧我来自火星,玩笑到此结束,下面切入正题。

本文的命题源自于这样的一个url,protocol://ip:port/chn/mode,比如说,dv://192.168.1.253:65001/1/1。如果我要解析出来各个部分,并把它们保存到各自的变量里面要怎么做?传统的C程序员会说用strtok慢慢取得各个部分,对于要转成int的用atoi,部分C++程序员也许会放弃strtok转用std::string当中的find系列成员函数(find/find_first_of...)。是的,我以前也是这么干的,两种方法都用过,当然也包括MFC里的CString的相关成员函数。现在,一种全新的方法源自于sscanf这个C语言函数。

无论你用C还是C++,sscanf和scanf这两个函数都不会太陌生,%d %s %f甚至%02d %.2f这些东西你也很熟,看了上面我说的正则表达式,也许你会写出这么一个正则表达式:[a-zA-Z]+://(/d{1,3}/.){3}(/d{1,3}):/d{1,5}//d{1,}//d,没错,这个正则表达式的IP部分有点问题,但是为了描述简单,暂时就这么用了。激动人心的时候到了,我要告诉你的是scanf以及sscanf实际上是支持部分正则表达式的,当然即使是到现在我依旧不敢肯定这个部分是否是ANSI的一部分,但是我的VS2005上没有问题,朋友的VS2003上也没有问题,至于VC6实在太古老暂时找不到测试。但是顺便说一句,VS2005上你用sscanf或者scanf他会出警告的,他说这两个函数不安全建议你用sscanf_s和scanf_s,我试了下推荐的两个函数又不支持这个功能了,比较囧了。

好了,具体说说sscanf的这个扩展功能吧(暂且这么叫)。sscanf提供的这个扩展功能其实并不能真正称为正则表达式,因为他的书写还是离不开%,而且也很局限。但是作为处理我上面说的url已经是绰绰有余了。sscanf的这个扩展功能支持[]表示支付范围,{}表示重复次数,^表示取非,*表示跳过。所以上面这个url的解析可以写成下面这个样子:

char url[] = "dv://192.168.1.253:65001/1/1"

sscanf(url,"%[^://]%*c%*c%*c%[^:]%*c%d%*c%d%*c%d",protocol,ip,port,chn,type);

解释一下

先取得一个最长的字符串,但不包括字串://,于是protocol="dv/0";

然后跳过三个字符(%*c),其实就是跳过://

接着取一个字符串不包括字符串:,于是ip=192.168.1.253,这里简化处理了,IP就当个字符串来弄,而且不做检查

然后跳过冒号取端口到port,再跳过/取通道号到chn,再跳过/取码流类型到type。

是不是觉得还不过瘾?我也觉得,接着举例。

sscanf("Phil/nChang","%[^/n]%*c%s",first_name,last_name);

解释:跳过一个换行符,取first_name和last_name

类似上面的sscanf("phil2360@gmail.com","%[^@]%*c%s",host);

基本上,这个东西用的不多,但是有时候很实用,让你的代码会很简洁,但是相比正则表达式,功能又显得简陋很多,怎么用,就看个人而定了,还是那句话,不是很确定这东西是不是ANSI的,所以不考虑移植又觉得很简洁那么用吧,考虑移植那么请三思,至于正则表达式,用regex或者boost库吧,哦,我说的是C++,C#本来就带了的!


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

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的值为 "123456/0!!!"

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

实验2:

"%3s"; ---------str的值为 "123/0!!!!!!"

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

实验3:

"aaaAAA""%[a-z]"; ---------str的值为 "aaa/0!!!!!!"

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

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

实验4:

"AAAaaaBBB""%[^a-z]"; ---------str的值为 "AAA/0!!!!!!"

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

实验5:

"%[A-Z]%[a-z]"; ---------段错误

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

实验6:

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

实验7:

; ---------str的值为 "!!!!!!!!!!"

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

实验8:

"AAAaaaBC=""%*[A-Z]%*[a-z]%[^a-z=]"; ---------str的值为 "BC/0!!!!!!!"

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

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

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

实验9:

int k;

"AAA123BBB456""%*[^0-9]%i"; ---------k的值为123

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

正则表达式和sscanf的更多相关文章

  1. Html5 canvas实现粒子时钟的示例代码

    这篇文章主要介绍了Html5 canvas实现粒子时钟的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. ios – 如何使用Objective C类中的多个参数调用Swift函数?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  4. ios – 使用大写符号在字符串swift中获取URL的正则表达式

    我尝试在文本中获取URL.所以,在此之前,我使用了这样一个表达式:但是当用户输入带有大写符号的URL时(例如Http://Google.com,它与它不匹配)我遇到了问题.我试过了:但什么都没发生.解决方法您可以使用正则表达式中的i内联标志关闭区分大小写,有关可用正则表达式功能的详细信息,请参阅FoundationFrameworkReference.(?ismwx-ismwx)Flagsetti

  5. 在Xcode4中,你可以更改用于显示隐形字符的字符吗?

    我更喜欢VisualStudio显示隐形的方式……

  6. ios – 应用程序商店描述特殊字符

    是不是可以在AppStore描述中使用像星星这样的特殊字符了?我得到这个错误:描述不得包含标记语言.说明不得包含以下字符:★提前致谢:)解决方法仍然允许一些unicode字符.以下字符已经过测试并仍然有效:◆√至于现在他们工作正常,但苹果可以随时再次改变条件.

  7. ios – 将数组中的字符转换为整数

    即使我搜索了文档,我似乎无法弄清楚如何做到这一点.我试图弄清楚如何将数组中索引处的字符转换为整数.例如,假设我有一个名为“容器”的字符数组,我无法弄清楚该怎么做:谢谢您的帮助!解决方法Swift并不容易在原始和类型表示之间进行转换.这是一个在此期间应该有所帮助的扩展:这使您可以非常接近您想要的:对于遇到此问题的任何工程师,请参阅rdar://17494834

  8. ios – Swift:递归值类型

    我有一个结构,我想要一个结构类型的全局变量?这个例子本质上是我实际创建的结构的简化版本.但是,它会抛出错误:有没有办法解决这个问题?

  9. ios – 如何在Swift 3中使用正则表达式?

    解决方法我相信.当没有其他选项适用时,将使用.allZeros.因此,使用Swift3,您可以传递一个空的选项列表或省略options参数,因为它默认为无选项:要么请注意,在Swift3中,您不再使用error参数.它现在抛出.

  10. ios – lldb断点在类目标c中的所有方法

    如何使用lldb在ObjectiveC类中的所有方法上自动设置断点?

随机推荐

  1. 法国电话号码的正则表达式

    我正在尝试实施一个正则表达式,允许我检查一个号码是否是一个有效的法国电话号码.一定是这样的:要么:这是我实施的但是错了……

  2. 正则表达式 – perl分裂奇怪的行为

    PSperl是5.18.0问题是量词*允许零空间,你必须使用,这意味着1或更多.请注意,F和O之间的空间正好为零.

  3. 正则表达式 – 正则表达式大于和小于

    我想匹配以下任何一个字符:或=或=.这个似乎不起作用:[/]试试这个:它匹配可选地后跟=,或者只是=自身.

  4. 如何使用正则表达式用空格替换字符之间的短划线

    我想用正则表达式替换出现在带空格的字母之间的短划线.例如,用abcd替换ab-cd以下匹配字符–字符序列,但也替换字符[即ab-cd导致d,而不是abcd,因为我希望]我如何适应以上只能取代–部分?

  5. 正则表达式 – /bb | [^ b] {2} /它是如何工作的?

    有人可以解释一下吗?我在t-shirt上看到了这个:它似乎在说:“成为或不成为”怎么样?我好像没找到’e’?

  6. 正则表达式 – 在Scala中验证电子邮件一行

    在我的代码中添加简单的电子邮件验证,我创建了以下函数:这将传递像bob@testmymail.com这样的电子邮件和bobtestmymail.com之类的失败邮件,但是带有空格字符的邮件会漏掉,就像bob@testmymail也会返回true.我可能在这里很傻……当我测试你的正则表达式并且它正在捕捉简单的电子邮件时,我检查了你的代码并看到你正在使用findFirstIn.我相信这是你的问题.findFirstIn将跳转所有空格,直到它匹配字符串中任何位置的某个序列.我相信在你的情况下,最好使用unapp

  7. 正则表达式对小字符串的暴力

    在测试小字符串时,使用正则表达式会带来性能上的好处,还是会强制它们更快?不会通过检查给定字符串的字符是否在指定范围内比使用正则表达式更快来强制它们吗?

  8. 正则表达式 – 为什么`stoutest`不是有效的正则表达式?

    isthedelimiter,thenthematch-only-onceruleof?PATTERN?

  9. 正则表达式 – 替换..与.在R

    我怎样才能替换..我尝试过类似的东西:但它并不像我希望的那样有效.尝试添加fixed=T.

  10. 正则表达式 – 如何在字符串中的特定位置添加字符?

    我正在使用记事本,并希望使用正则表达式替换在字符串中的特定位置插入一个字符.例如,在每行的第6位插入一个逗号是什么意思?如果要在第六个字符后添加字符,请使用搜索和更换从技术上讲,这将用MatchGroup1替换每行的前6个字符,后跟逗号.

返回
顶部