Chinaunix

标题: 学习分享--正则中的环视 [打印本页]

作者: jeffreyst    时间: 2014-04-18 17:00
标题: 学习分享--正则中的环视
本帖最后由 jeffreyst 于 2014-04-18 17:15 编辑

网上有关于环视的解释,有些写的很长,很佩服这些这么耐心解释正则环视的大神(绝无讽刺之意),
但是我实在没有太多的耐心把这些内容看完,在此深深的鄙视下自己^-^

在此分享下我对正则环视的理解,在下也是初学,说的不好或者不对的地方,请各位大神指正,多谢!

环视的作用:确定一个位置
下面看下一个从ifconfig中过滤ip地址的例子(获取下面红色标注的IP)
[root]# ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:69954 errors:0 dropped:0 overruns:0 frame:0
          TX packets:69954 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:5139078 (4.9 MiB)  TX bytes:5139078 (4.9 MiB)

p4p1      Link encap:Ethernet  HWaddr A4:1F:72:79:0C:8D  
          inet addr:10.84.22.21  Bcast:10.84.22.255  Mask:255.255.255.0
          inet6 addr: fe80::a61f:72ff:fe79:c8d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:121702347 errors:0 dropped:0 overruns:0 frame:0
          TX packets:133507811 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:42562340126 (39.6 GiB)  TX bytes:58317218304 (54.3 GiB)

方式1:ifconfig | grep -oP "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"

只看这个正则就感觉比较“笨”,呵呵!这样的结果如下,但是不精确。
127.0.0.1
255.0.0.0
10.84.22.21
10.84.22.255
255.255.255.0
最后还要过滤下,只显示我们需要的两个IP,ifconfig | grep -oP "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" | sed -n '1p;3p'

方式2:

看下上面ifconfig显示的内容,我们就很容易发现两个IP前都有一个字串“ inet addr:”
如果使用一种方法把要匹配的位置指定到“ inet addr:”后面就好了,这时我们就可以用到正则的环视了...环视的使用场景就是这样...
现在我们重新写下这个语句:ifconfig | grep -oP "(?<=inet addr:)[0-9\.]+";这个黑色高亮的部分就是逆序环视了
所谓环视,就是找位置,顺序环视是找字串左面的位置,逆序环视是确定字串右面的位置,那上面的逆序环视确定的位置就是从“inet addr:”开始了...
上面语句就是匹配从“inet addr:”后面开始,由数字和“.”组成的字串,那就是要找的IP了。
执行结果是:[root]# ifconfig | grep -oP "(?<=inet addr:)[0-9\.]+"                       
127.0.0.1
10.84.22.21

方式3:

如果我们只想要IP:10.84.22.21
我们很容易发现,这个IP是在字串“inet addr:”和 “ Bcast”之间的,修改下上面的语句为:
ifconfig | grep -oP "(?<=inet addr:).*(?= Bcast)"
执行结果就是我们想要的IP:10.84.22.21
我们在语句中又加了一个括号,目的就是要再确认一个位置,这个位置就是要定做“ Bcast”左面,这个括号中的内容就是顺序环视了
一个逆序环视指定边界从表达式的右边开始(我们想要的IP的左边界),
并上一个顺序环视,指定一个结束位置是到表达式的左边(确定了IP的右边界),那么IP的位置就确认了,表达式“.*”就能匹配到这个IP的内容。

总结下,上面说的都是肯定环视,就是匹配到表达式后做的操作,具体的格式如下:

(?<=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Expression
(?=Expression) 顺序肯定环视,表示所在位置右侧能够匹配Expression

否定环视的格式如下:
(?<!Expression) 逆序否定环视,表示所在位置左侧不能匹配Expression
(?!Expression) 顺序否定环视,表示所在位置右侧不能匹配Expression
由于否定的逆序的应用场景我还没有遇到,在这里就不举例了,但是原理应该和上述的类似...
作者: jeffreyst    时间: 2014-04-18 17:02
自己先顶下
顺便问下,帖子中的表情怎么去掉?
作者: laliheyi    时间: 2014-04-18 17:03
禁用表情{:3_182:}
作者: Shell_HAT    时间: 2014-04-18 17:04
Nice work!
作者: jeffreyst    时间: 2014-04-18 17:10
本帖最后由 jeffreyst 于 2014-04-18 17:11 编辑

回复 3# laliheyi

   
    那个表情对应的字符是“:”和“)”
   在下愚钝,该如何修改,麻烦具体说下,多谢!
作者: Shell_HAT    时间: 2014-04-18 17:13
回复 5# jeffreyst


    顶楼那个帖子,点击“编辑”,勾选右侧的“禁用表情”
作者: jeffreyst    时间: 2014-04-18 17:20
回复 6# Shell_HAT


    搞定,多谢HAT哥,上次看到大神用环视,一直很纠结怎么用,今天发奋研究了下...
    把研究成果发了出来,请大家帮忙看看有没有什么地方理解的不正确...献丑了!
作者: cxm240    时间: 2014-04-18 18:00
不错..........
作者: blackold    时间: 2014-04-18 18:10
回复 1# jeffreyst


    总结就有进步,好!
作者: love_shift    时间: 2014-04-18 18:36
好像比零宽断言好听~
作者: expert1    时间: 2014-04-20 22:11
好贴好贴,学习一下。
作者: cao627    时间: 2014-04-21 10:27
个人觉得还是还是翻译为“断言”比较好。至于加上零宽二字就没必要了。

也没必要将  (?<=Expression)  理解为:匹配的是一个位置,这样理解没错,但不好记。

这样比较好记
(?<=Expression)pat  :pat断言它自己左边有Expression。即左边没有Expression的pat  不是符合条件的pat。

所以“断言”比“环视”好。
作者: Herowinter    时间: 2014-04-21 10:37
回复 12# cao627
英文叫Zero-Width Assertions,好像是直译的。


   
作者: cao627    时间: 2014-04-21 10:48
@Herowinter
可能老外也不统一,有叫L​o​o​k​a​r​o​u​n​d的。
作者: jeffreyst    时间: 2014-04-21 11:25
回复 12# cao627


    怎么说呢?其实我对零宽断言和环视之间的区别理解不是太深,
    我觉得零宽断言这个定义的范围应该比环视的定义大一些,毕竟零宽断言包含其他一些“^”等锚点,
    而本文说的环视,是通过一些符号+Expression来确定的Expression前/后的位置,
    这个位置的确定是有参照的字串和方向的(相对于Expression的位置),所以个人认为环视比较准确,毕竟有顺序和逆序之分。

    要是从记忆的角度上来说的话,个人觉得这个概念的意义就不是那么大了,反而是它的应用场景比较重要,
    它本质上就是来找到一个位置,既然是个位置,那么可以理解成字串宽度为0,这个符合零宽断言的字面意思。
    Expression前面的字符决定着这个位置在Expression的方向以及是肯定匹配还是否定匹配的。


作者: zxy877298415    时间: 2014-04-21 11:37
回复 1# jeffreyst
[root@hardowrking scripts]# ifconfig
eth0      Link encap:Ethernet  HWaddr 08:00:27:04:61:98  
          inet addr:192.168.137.32  Bcast:192.168.137.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:642 errors:0 dropped:0 overruns:0 frame:0
          TX packets:234 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:75701 (73.9 KiB)  TX bytes:38243 (37.3 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:5775 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5775 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:6078345 (5.7 MiB)  TX bytes:6078345 (5.7 MiB)

[root@hardowrking scripts]# ifconfig | grep -oP "[0-9]{3}\.[0-9]{3}\.[0-9]{3}\.[0-9]{3}"
192.168.137.255

我这个很精确啊!


   
作者: jeffreyst    时间: 2014-04-21 11:41
回复 16# zxy877298415


    你的IP应该是这个吧:192.168.137.32
    这个语句只是个引子,我的目的是通过环视来匹配这个ip,顺便说下使用环视匹配的过程而已
作者: zxy877298415    时间: 2014-04-21 11:45
回复 17# jeffreyst
嗯,好帖子学习了,如果位数固定的话,还是能用方法一


   
作者: blackold    时间: 2014-04-21 11:55
回复 15# jeffreyst


   
个人觉得,你的理解已经很深了。

lookaround 和 zero-width assertion 本来就是两个不同的概念。

显然,"lookaround zero-width assertion" 只是一种特殊的 zero-width assertion。
如你所说 zero-width assertion 的范围更广, 包括 ^ $ \b等等。

至于如何翻译,自己喜欢就好。关键是要明白是怎么回事。 往往有五花八门的翻译,
其实表达的都是同一个意思。

作者: cao627    时间: 2014-04-21 12:41
本帖最后由 cao627 于 2014-04-21 12:43 编辑

@jeffreyst
毕竟零宽断言包含其他一些“^”等锚点

只觉得的“环视”的话光看字面不知说云。“断言”二字却能望文生意,至于零宽不零宽根本没当回事。
作者: jeffreyst    时间: 2014-04-21 13:50
回复 19# blackold


    嗯嗯,黑哥说的一针见血
作者: prcardin    时间: 2014-07-12 17:02
mark学习!
作者: qq58945591    时间: 2014-07-13 21:59
学习了,唉,以前不懂老是用笨办法,一次又一次的截取,先普通grep,再sed, 这个就一次成型,简洁
作者: Buring__    时间: 2014-07-16 17:17
  很赞,
作者: zerostudy    时间: 2014-07-17 08:51
学习,不错~
这个东东之前在正则30分入门看过。
作者: lolizeppelin    时间: 2014-07-17 13:24
赶紧转了 ~ mark
作者: jeffreyst    时间: 2014-07-17 13:52
回复 25# zerostudy


    这个正则30分组入门还不错,但是里面有个懒惰模式,还没学会...
    http://www.jb51.net/tools/zhengze.html
作者: zerostudy    时间: 2014-07-17 14:13
回复 27# jeffreyst

懒惰这个反而好记哦,有些就可以不用分析他的匹配规则,直接.*?,来达到效果。

作者: jeffreyst    时间: 2014-07-17 14:30
回复 28# zerostudy


    嗯嗯,用grep简单试了试,没看到效果
作者: zerostudy    时间: 2014-07-17 14:41
回复 29# jeffreyst
  1. [root@localhost awk]# cat p
  2. inet addr:10.16.66.106  Bcast:10.16.66.255  Mask:255.255.255.0 inet addr:10.16.66.108  Bcast:10.16.66.255  Mask:255.255.255.0
  3. [root@localhost awk]# cat p | grep -oP "(?<=inet addr:).*(?= Bcast)"
  4. 10.16.66.106  Bcast:10.16.66.255  Mask:255.255.255.0 inet addr:10.16.66.108
  5. [root@localhost awk]# cat p | grep -oP "(?<=inet addr:).*?(?= Bcast)"
  6. 10.16.66.106
  7. 10.16.66.108
  8. [root@localhost awk]#
复制代码
有效果吧
作者: jeffreyst    时间: 2014-07-17 16:13
回复 30# zerostudy


    确实看到了区别,但是理解的依然不是太好,尤其是看到下面的解释:


表5.懒惰限定符
代码/语法        说明
*?        重复任意次,但尽可能少重复
+?        重复1次或更多次,但尽可能少重复
??        重复0次或1次,但尽可能少重复
{n,m}?        重复n到m次,但尽可能少重复
{n,}?        重复n次以上,但尽可能少重复

尽可能少重复,是什么意思...
帮忙解释下,多谢先~
作者: cxm240    时间: 2015-01-17 15:37
看起来不错,有空学习下
jeffreyst 发表于 2014-07-17 13:52
回复 25# zerostudy





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2