sigil吧 关注:2,353贴子:13,974
  • 8回复贴,共1

用正则表达式匹配「不含某些字符」的内容——「环视」入门

只看楼主收藏回复

注 1 :本文需要一定正则表达式基础
注 2 :Sigil 官方建议依照 Python 的方式使用 Sigil 内置的正则表达式功能,因此需要帮助时可以查找 Python 的解决方案
我们都知道,正则表达式可以匹配到各种各样的「字符」,但除此以外,实际上正则表达式还能匹配到「位置」。
比如我们常用的「 ^ 」(行首)、「 $ 」(行尾)就是典型的例子。每个「字符」在正则表达式中都是一个「宽度」( length,直译是「长度」),「 abc 」这样三个字符,宽度就是 3,用来匹配「一个任意字符」的「 . 」宽度就是 1 。
而字符与字符之间的位置,宽度就为零,能匹配到这些「位置」的「元字符」,也是「零宽度」。其中就有一组被称为「环视( Lookahead and Lookbehind )」的元字符,用于根据「这个位置的前面(后面)存在(不存在)某某字符」来进行定位,它们的全称是「环视零宽断言( Lookahead and Lookbehind Zero-Length Assertions )」。
这就是本文要介绍的内容。
关于「环视」或者「零宽断言」的介绍网上有很多,但基本上都是概念的说明,初学者在使用的时候往往会很费解,搞不清。造成这个问题的很大一部分原因就在于,初学者并不知道这里的「向前(或称『向左』)」和「向后(或称『向右』)」导致是以什么为基准的。因此本文将会结合图象来进行讲解。
基本定义:
(?<=abc)——逆序肯定环视,表示所在位置左侧能够匹配 abc
(?<!abc)——逆序否定环视,表示所在位置左侧不能匹配 abc
(?=abc)——顺序肯定环视,表示所在位置右侧能够匹配 abc
(?!abc)——顺序否定环视,表示所在位置右侧不能匹配 abc
看起来好像很容易懂,但是实际使用的时候往往又让人挠头,感觉并不能取得预期的结果。接下来,我们就一个个来看。
例子就是下面这组字符串,大家可以在 Sigil 中试试(注意用代码视图)。
abcd1234
1234abcd
aaaa1234
bbbbabcd
1、(?<=abc)——逆序肯定环视
逆序的意思,就是向前(左)查找。
如果我们要匹配到「 abcd1234 」中的「 1234 」,但不包括「 abcd 」,写法是
(?<=abcd)1234

当匹配到位置 5 的时候,整个表达式都满足,因此返回结果。而由于正则表达式的结果是从匹配成功的位置之后开始返回内容的,因此,只有「 1234 」会被返回。
2、(?<!abc)——逆序肯定环视
和肯定环视相反,需要是前面「不是」「 abcd 」的内容:
(?<!abcd)1234
这样将能匹配到上面例子的第二、三行。
注意了,这个是能够匹配到第二行「 1234abcd 」中的「 1234 」!
为什么会这样?其实我们稍微分析一下就知道了:

3、(?=abc)——顺序肯定环视
顺序的意思,就从所在位置向右(后)来查找,我们现在回过头来看看匹配「 1234abcd 」的那个例子,我们把逆序换成顺序:
(?=abcd)1234
诶,查找不到了!为什么会这样呢?

可以看到,问题的关键就是「零宽断言」仅仅是用于「定位」的,当定位成功后,就从相应的位置开始往后匹配,如果该位置后面没有相应的内容,匹配也会失败。
这是很多初学者感到迷惑的地方,但只要进行一下分析,就能明白问题所在。
4、(?!abc)——顺序否定环视
和肯定环视相反,需要是后面「不是」「 abcd 」的内容:
(?!abcd)1234,你会发现居然能匹配到一至三行,第二第三行还能理解,那为什么会匹配到「 abcd1234 」呢?
我们再画个图来分析分析:

这样就很容易理解,为什么会匹配到第一行中的「 1234 」了。


IP属地:广东1楼2017-06-21 21:42回复
    看着头痛


    IP属地:北京来自iPhone客户端2楼2017-06-22 20:22
    回复
      简单来说就是 前面是exp的位置 前面不是exp的位置 后面是exp的位置。后面不是exp的位置


      IP属地:北京来自iPhone客户端3楼2017-06-23 23:18
      回复
        收藏了,对整理排版大有用处


        IP属地:广东来自Android客户端4楼2017-10-03 21:42
        回复
          谢谢,技术含量高。


          来自Android客户端5楼2017-10-11 08:25
          回复
            好复杂,蒙蒙中。。。


            6楼2017-10-11 11:13
            回复
              受教了,慢慢研究


              IP属地:北京来自Android客户端7楼2019-04-21 19:03
              回复
                强啊,受教了


                IP属地:上海8楼2023-10-13 20:24
                回复
                  强啊,第一次彻底搞懂了零宽断言。原来看到就头疼。


                  IP属地:上海9楼2023-10-21 19:39
                  回复