《精通正则表达式》第三版 1-2 量词:问号,加号,星号

上一篇:《精通正则表达式第三版》读书笔记1

可选项元素(量词:)

例子1:colou?r

现在来看colorcolour的匹配。他们的区别在于,后面的单词比前面的单词多一个u,我们可以用colou?r这个正则表达式来解决这个问题。元字符?(问号),代表可选项?加在一个字符的后面,就表示此处允许出现这个字符,也可以不出现这个字符,这个字符的出现并非匹配成功的必要条件。
u?中的元字符与我们之前看到的元字符都不相同,它只作用不之前紧邻的元素。因此colou?r的意思是:先依次匹配字符c,o,l,o,然后是u?,最后是r

u?是必然能匹配成功的,有时候它会匹配字符u,其他时候则不匹配任何字符。关键在于u是否出现u?都是匹配成功的。但是这并不意味着,任何包含?的正则表达式都永远能匹配成功,例如colou?都能在semicolon中匹配成功,(colo匹配semicolon中的colou?则什么都不匹配)。但是之后的r无法匹配,所以最终正则表达式colou?r无法匹配semicolon
实例:
questionMark.txt:

color colour semicolon

命令:egrep "colou?r" questionMark.txt,匹配效果如下。
这里写图片描述
grep好像不支持可选元字符?,上面的命令如果用grep "colou?r" questionMark.txt将无法匹配。
这里写图片描述

例子2

来看另一个例子,我们需要匹配表示74日的文本(July fourth)的文本,其中月份可能写作July或者是Jul,而日期可能写作fourth,4th,或者4。显然我们可以使用(July|Jul).(fourth|4th|4),不过也可也使用其他方法来结局这个问题。
首先我们把(July|Jul)缩短为July?。去除了多选元字符|之后就没必要保留括号了。所以July?显然更加简洁。于是得到新的正则表达式:July?.(fourth|4th|4)

现在看看第二部分,我们可以把4th|4简化为4(th)?,可以看到现在作用的是整个括号了,括号内可以是任意复杂的正则表达式,但是从括号外面来看它们是一个整体。可以看到这里的括号()用来限定的作用对象。同样的道理使用括号()还可以用来限定其他类似元字符的作用对象,这是括号()的主要用途之一。
现在正则表达式变成了July?.(fourth|4(th)?)。尽管这个正则表达式包含了许多元字符,但是理解起来并不困难。
实例:
dates.txt:

Wen July 4 17:39:57 CST 2018
Wen Jul 4th 17:39:57 CST 2018
Wen Jul fourth 17:39:57 CST 2018

使用正则表达式July?.(fourth|4(th)?)匹配,命令:egrep "uly?.(fourth|4(th)?)" dates.txt,执行结果如下。
这里写图片描述
使用正则表达式(July|Jul).(fourth|4th|4)进行匹配,命令:egrep "(July|Jul).(fourth|4th|4)" dates.txt,匹配结果如下。
这里写图片描述

其他量词:重复出现

加号+和星号*的作用于问号?类似,元字符+表示之前紧邻的元素可以出现一次或多次,而元字符*表示之前紧邻的元素可以出现任意多次,甚至不出现。换种说法就是:
- *表示匹配尽可能多的次数,如果实在无法匹配也不要紧。
- +的意思是匹配尽可能多的次数,但是至少要匹配一次,如果连一次也无法匹配,则匹配失败。

量词:问号?,加号+,星号`

问号?,加号+,星号*这三个元字符统称为量词,它们限定了作用元素的匹配次数。

三个量词的异同

和问号一样量词星号*也是永远不会匹配失败的,区别值在于它们的匹配结果,而加号+在无法进行任何一次匹配是,会报告匹配失败。
举例来说:
.?能有匹配一个可能出现的空格,但是.*能匹配任意多个个空格。

量词应用实例

实例1:匹配<H[1-6]>的这样的HTML tag

作者的例子:
我们可以用着两个量词来简化上一篇文章中的<H[1-6]>的例子,按照HTML规范,在tag结尾的>字符之前可以出现任意长度的空格,例如<H3___>或者<H4_________>
等等(这里用下划线代替空格,因为在markdown里写空格好像显示出来)。
.*加入正则表达式中可能出现空格的位置,就得到了:H[1-6].*。这个正则表示是依然能匹配<H1>,因为空格并不是必须出现的,单其他形式的tag也能匹配。


我的实例验证:

<!doctype html>
<html lang="en">
<head>
        <meta charset="UTF-8">
</head>

<body>
        <h1   >一级标题</h1>
        <h2    >二级标题</h1>
        <h3     >三级标题</h1>
        <h4      >四级标题</h1>
        <h5       >五级标题</h1>
        <h6        >六级标题</h1>

</body>

</html>

使用正则表达式[Hh][1-6].*,进行匹配: egrep "[Hh][1-6].*" CharSet.html
这里写图片描述
可以看到,什么都没匹配到,就匹配到一些空行,看来作者这里写的有问题,还是不要用点号.代替空白符的好,而是使用空白符\s,我这里把正则表达式为[Hh][1-6]\s*
执行命令:egrep "[Hh][1-6]\s*" CharSet.html
这里写图片描述
从匹配的结果中可以看到,空白符也匹配到了,已经用红色标记出来了。当然上面也没有完整匹配到HTML标签,应该加入HTML标签的开始符合结束符<>,修改后的匹配命令为:egrep "<[Hh][1-6]\s*>" CharSet.html
这里写图片描述
可以看看到上面成功匹配的HTML标签的开始符如<h1>,但是结束符</h1>,没能匹配到。观察这了两个标签可以看出,结合标签多了一个反斜杠/,这个时可以加入问号这个量词,这样就能同时匹配HTML的开始符和结束符。修改后的正则表达式为:</?[Hh][1-6]\s*>,执行命令: egrep "</?[Hh][1-6]\s*>" CharSet.html,匹配效果如下。
这里写图片描述
还有一个就是,在Ubuntu终端中,空白符是默认不显示的,可以用鼠标选中这些匹配的结果,就可看到空白符是不是被选中了,如果选中了会有标记红色。


实例2:匹配类似<HR SIZE=14>这样的HTML tag

接下来看类似<HR SIZE=14>这样的HTML tag,它表示一条高度我14像素的穿越屏幕的水平线,与<H3>的例子一样,在最后的尖括号之前可以出现任意多个空格。此外在等号=两边也允许出现任意多个空格。最后HR和SIZE之间最少有一个空格。为了简便处理使用点号.来匹配空空格,然后该空格后面可以有多个空格可以用.*表示。这样的的正则表达式为<HR..*SIZE.*=.*14.*>。虽然这样能实现效果,但是还是用.+来替代..*比较简洁。所以得到的正则表达式为:<HR.+SIZE.*=.*14.*>


验证:
HR.html:

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>测试匹配水平线</title>
</head>

<body>
    <hr size=14>
    <hr  size=14>
    <hr  size =14>
    <hr  size = 14>
    <hr  size  = 14 >
</body>

</html>

使用正则表达式<HR..*SIZE.*=.*14.*>进行匹配: egrep -i "<HR..*SIZE.*=.*14.*>" HR.html
使用正则表达式<HR.+SIZE.*=.*14.*>进行匹配:egrep -i "<HR.+SIZE.*=.*14.*>" HR.html
这里写图片描述
可以看到两个正则表达式匹配的效果都是一样的


尽管上面的<HR.+SIZE.*=.*14.*>这个正则表达式不受到空格个数的限制,单他仍然后tag中水平直线大小约束,我们要找的不仅仅是高度为14tag,而是所有的tag,所以我们必须用能有匹配普通数值的表达式来替换上面的14。在这里,数值是由一位或者多位数值构成的[0-9]可以表示一个数字,因为至少出现一次,所以使用加号+量词,结果就是使用[0-9]+带代替<HR.+SIZE.*=.*14.*>中的14。一个字符组是一个元素(一个元素最终只匹配一个字符),所以它可以直接加上加号+,星号*,和问号而不需要加括号限定。
这样我们就得到了正则表示式:<HR.+SIZE.*=.*[0-9]+.*>


现在使用这个新的正则表达式<HR.+SIZE.*=.*[0-9]+.*>匹配上面的HR.html文件,命令: egrep -i "<HR.+SIZE.*=.*[0-9]+.*>" HR.html
这里写图片描述


<HR.+SIZE.*=.*[0-9]+.*>这个正则表达式看起来比较诡异,这是因为这里使用了星号和加号作用的对象空格,人们习惯吧空格跟普通的字符区分开。在阅读正则表达式时,要改变这种习惯,因为空格也是普通字符之一,它与a,b,c0,1,2…没有任何差别。

实例3:同时匹配<HR><HR SIZE=14>这样的HTML tag

我们继续这个例子,如果尺寸这个属性也是可选的,也就是说<HR>就代表默认高度的直线(同样在>之前也可能出现空格)。现在修改上面的正则表达式实现这个功能。

可选项:(子表达式)?

可选项的意思是可以出现一次,也可以不出现,例如上面的<HR><HR SIZE=14>中,SIZE=14就是可选出现的。这样的可选项可以使用问号量词?实现,因为可选项SIZE=14多余一个字符,所以要用括号()进行限定,可选项的正则表达式为(.+SIZE.*=.*[0-9]+.*)?,所以上面的问题的最终的正则表达式为:<HR(.+SIZE.*=.*[0-9]+.*)?.*>
要注意的是结尾的.*出现在可选项(...)?之外,这样就能应付<HR.>之类的情况。同样要注意的时括号里面的SIZE前面的.+也不能少,如果把它拿到括号外,则HR之后就必须要有一个空格,这样即使SIZE没有出现,也是必须要有一个空格。这样就无法匹配<HR>这种情况了。
上面的正则表示式中把可选的字表达式(.+SIZE.*=.*[0-9]+.*)?.*交换一下也是可以的:<HR.*(.+SIZE.*=.*[0-9]+.*)?>


代码验证:

修改后的HR.html:

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>测试匹配水平线</title>
</head>

<body>
    <hr size=14>
    <hr  size=1>
    <hr  size =2>
    <hr  size = 3>
    <hr  size  = 4 >
    <hr>
    <hr  >
</body>

</html>

使用上面的正则表达式<HR(.+SIZE.*=.*[0-9]+.*)?.*>进行匹配, egrep -i "<HR(.+SIZE.*=.*[0-9]+.*)?.*>" HR.html
这里写图片描述
可以看到不管是<hr>还是<hr >,还是<hr size=14>以及有空格的情况。<HR(.+SIZE.*=.*[0-9]+.*)?.*>这个正则表达式都能匹配到。
使用另个一个正则表达式<HR.*(.+SIZE.*=.*[0-9]+.*)?>进行匹配,egrep -i "<HR.*(.+SIZE.*=.*[0-9]+.*)?>" HR.html
这里写图片描述


要注意的是,每个量词都规定了匹配成功至少需要的次数的下线,以及尝试匹配次数的上限,对于量词和量词*,下限是0,而量词+下限是1。而对于+*这两个量词,上限是无穷大,而。量词的上限是1

量词小结

序号量词次数下限次数上限描述
101可以出现一次,也可以不出现(单次可选)
2*0无穷大可以不出现,也可以出现任意次(任意次均可)
3+1无穷大可以出现无数次,但至少出现一次(至少一次)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
正则表达式是一种用于匹配、查找和替换文本的强大工具。它由一系列字符和特殊字符组成,可以用来描述字符串的模式。以下是正则表达式的介绍: 1. 字符匹配:正则表达式可以用来匹配指定的字符。例如,表达式 "abc" 可以匹配字符串中连续出现的 "abc"。 2. 字符类:使用方括号 [] 可以定义一个字符类,表示匹配其中任意一个字符。例如,表达式 "[abc]" 可以匹配字符串中的 "a"、"b" 或 "c"。 3. 量词:使用量词可以指定匹配字符的数量。例如,"*" 表示匹配前面的字符零次或多次,"+" 表示匹配一次或多次,"?" 表示匹配零次或一次。 4. 特殊字符:正则表达式中有一些特殊字符具有特殊的含义,如 "." 表示匹配任意字符,"\d" 表示匹配数字,"\w" 表示匹配字母、数字或下划线等。 5. 边界匹配:使用 "^" 表示匹配字符串的开头,"$" 表示匹配字符串的结尾。例如,表达式 "^abc$" 只能匹配整个字符串为 "abc" 的情况。 6. 分组和引用:使用小括号 () 可以将一部分正则表达式进行分组,并且可以在后续的表达式中引用。例如,表达式 "(ab)+\1" 可以匹配 "abab"。 7. 转义字符:使用反斜杠 \ 可以对特殊字符进行转义,使其失去特殊含义。例如,表达式 "\." 可以匹配字符串中的点号。 8. 替换:正则表达式不仅可以用于匹配,还可以用于替换。通过使用替换符号和替换字符串,可以将匹配到的部分替换为指定的内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值