C#正则表达式(3):注释,分组,向后引用,零宽断言,贪婪

注释

 

任何程序语言都会有注释.不然很多代码不容易看懂啊.像正则表达式这种表达式如果来个几千行,没一点注释,你想不看得吐血都难啊.

注释的格式是(?#comment)其中comment就表示注释的内容比如abc[\d(?#this means digit)]* 它就等同于abc[\d]*

不过这样加注释更容易让人晕.所以大部分时候用的是那一种方式,是要结合函数里的参数一起用.RegexOptions.IgnorePatternWhitespace要加上这个参数

下面以#开头直到一行结束都是注释内容

abc       #this it start

[\d]       #this means digit

*           #this means zero times or more than zero times

具体用法是这样的string pattern = @"abc     # this is start

                                                        [\d]        #this means digit

                                                          * ";

string source = "this contains abc123 and other";

string result = Regex.Match(source,pattern,RegexOptions.IgnorePatternWhitespace).Value;

分支

 

前面有讲到在小括号中用|符号表示其中任选一个.其实就整个正则表达式的pattern中也可以用|来表示分支条件

比如ab[3-8]*|cd[1-3]+|ef[0-1]*这就表示三个分支,从左到右匹配,如果第一个分支匹配了就不用再管后面的分支了.其实这和C#的逻辑判断中的与或判断是一样的

比如有两个布尔变量a和b则if(a||b)中如果a为真则不会再去管b了

 

分组

我们在前面有用大括号{}来指定单个字母出现多少次,比如w{3}表示w连续出现三次.那如果是一串字符的话怎么整呢.我们会联想到算术符号里面的优先级问题,比如乘除号比加减号优先级高.要想使加减号先执行操作可以用个小括号把它们括起来.那在这儿同样把一串字符括起来就行.

比如(arwen){3}表示字符arwen重复三次. (ab[cde]*){4}表示ab[cde]*重复4次.反正用个()括起来后里面就被当作一个单元,一个整体了.专业点说法就叫分组

另外貌似用$加一个数字可以引用前面的分组.例如

string str = @"123abc";

string str = Regex.Replace(str,@(\d+)\w+, @"$1+456"); \\结果是123+456

(\d+)是匹配了123并把它做为一个组,$1就是引用了这个组

 

后向引用

 

后向引用,这名字听起来别扭,其实简单点讲就是在后面的匹配中又用到前面的某个分组.那如果在后面某个地方的匹配中要再次用到那个分组咋整呢?简单点的简单的做法把那个分组再照写下就得了呗.

比如(arwen){2}123abc(arwen){3}.但这样看起来有点冗余,于是就整个偷懒的办法出来.给每个分组起个名字,直接用组名来表示那个分组.如果你不直接命名会默认按分组从左到右出现的顺序命名为1,2,3...比如上面的例子最先出现的(arwen)命名为1,再出现个(arwen)命名为2,假如后面还来个(james)那命名为3

有个分组的名字后,上面的例子可以简写为(arwen){2}abc\1{3}引用分组的格式是一个斜杠\加组名

你还可以自己显式为每个组起个名字,格式是(?<name>exp)或者(?'name'exp)其中name是分组的名字,exp是分组中的内容.?就只是标识符而已.假如我要给分组(arwen)取名为a的话就这样写(?<a>arwen)这样开头的例子又可以写为(arwen){2}\a{3}

除了给分组默认取名或显式取名外还可以不给它取名格式是(?:exp)比如把分组(arwen)改成(?:arwen)就表示这个分组没名字.你后面不能通过某个名字去引用它.那这样做有什么意义呢?因为除这在这里我们看到分组名有用外,当通过Regex.Match(string source,string pattern)这个函数匹配取得结果后还可以做更详细的一些分析,那时也会用到分组名的.如果你想忽略掉某个位置的分组信息就可以显式的指定分组没有名字.

 

零宽断言

 

我们前面的一些简单匹配,都是先知道要匹配的子字符的一些信息,然后用些元字符和限制字符来表示它.进而匹配出结果.这是直接的匹配方式.还可以通过一些间接的匹配信息,比如知道子字符串前面有啥字符,屁股后面跟着些啥字符来匹配.

于是出现了零宽断言这个怪怪的名词,其实它代表的意思是这样,零宽表示那个表达式不占用地方,宽度为0,比如前面说的^$匹字符串的开头或结尾.它不占用地方,只表示开头或结尾这样一个位置概念.至于断言嘛是逻辑理论里面的一个说法.简单的说就是做判断了,下结论了.

零宽度正预测先行断言(?=exp)  它表示某个字符串背后跟着字符串exp比如.*(?=fool)表示某个字符以fool结尾.如果有字符you are afool.则匹配到的子字符是you are a

零宽度正回顾后发断言(?<=exp) 它表示某个字符串前面有字符串exp比如(?<=fuck)表示某个字符串前面有fuck.如果有字符fuck you则匹配的结果是 you

有了有通过前面或后面有某个字符串来判断,自然就可以有通过前面或后面没有啥字符来判断.这也是相反的意思.表示方法也差不多,只是=号变!

零宽度负预测先行断言 (?!exp) 它表示某个字符串后面没有跟着exp比如hao(?!\d)表示字符hao后面没紧跟着数字,如果有字符hao123,则不能匹配.如果是字符hao 123则匹配到hao

零宽度负回顾后发断言 (?<!exp)它表示某个字符串前面没有exp比如(?<!\d)hao表示字符串hao前没有数字.如果有字符123hao则匹配失败.如果是字符123 hao则匹配到hao

 

其实像啥零度断言这 类术语太让人纠结了,你干脆别去管他好了.就直接想象成前面有,后面有,前面没有,后面没有这样的通俗易懂的词好了

贪婪与懒惰

 

我们知道由于匹配的条件往往很模糊,所以匹配到的结果可以是不同的,比如有字符anrwen,用a.*n去匹配.那an和anrwen都是符合条件的结果

一匹配到an就不再匹配下去了,自然是很懒的做法,所以叫懒惰匹配.具体意思就是说尽可能匹配短的字符

而相反的情况就是贪婪匹配,尽可能匹配多的字符

默认的做法是贪婪匹配.所以上面的例子匹配的结果是anrwen

如果我们想得到an的结果,则要这样写a.*?n 多加个问号

至于这个?号在什么情况下用呢,自然是有出现让某个字符重复多次的限定符出现时用

比如* + ? {n}这些符号出现时就可以用,变成*?  +?  {n}?

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值