谈谈regex (?:) (?=) (?!) (?<=) (?<!)

一、简介(?:pattern)、(?=pattern)、 (?!pattern)、 (?<=pattern)、 (?<!pattern)

这是我做的一张思维导图,说一个容易被忽视的地方,就是零宽断言会匹配出任何满足pattern的位置,而不是像捕获组一样下次匹配是在上次匹配记录之后开始的。

例如:

    import re       
    s = "1234567890"
    pattern1 = "(\d{2})"  # 捕获组匹配
    print(re.findall(pattern1, s))
    # ['12', '34', '56', '78', '90']
    """
    care:
    捕获组匹配下次匹配是从上次匹配结果后开始匹配 而不是['12', '23', '34',...]
    """
    print(re.sub(pattern1, ",", s))
    # , , , , ,

    pattern2 = "(?=\d{2})"  # 非捕获组匹配
    print(re.findall(pattern2, s))
    # ['', '', '', '', '', '', '', '', '']
    """
    care:
    匹配的是"\d{2}"这个模式的头位置, 而不包含"\d{2}"这个模式
    """
    print(re.sub(pattern2, ",", s))
    # , 1, 2, 3, 4, 5, 6, 7, 8, 90
    """
    care:
    12满足\d{2}这个模式,匹配到12之前的这个位置,所以此时替换后结果为, 1234567890
    23满足\d{2}这个模式,匹配到23之前的这个位置, 所以此时替换后结果为, 1, 234567890
    依次类推...
    到最后一个数字0是不满足\d{2}这个模式了,所以最后一个替换出现在90这一次, 1, 2, 3, 4, 5, 6, 7, 8, 90
    """

 

二、快速理解零宽断言

  举个栗子,有以下文本:

1 我要吃好吃的~我要下班~我要睡觉
2 我不要吃好吃的~我要下班~我要睡觉
3 我要吃好吃的~我要下班3~我不要睡觉

伪代码:
positive_lookahead_regex = 我要下班~(?=我要睡觉)  
//这里的含义为 匹配"我要下班~"这个模式,然后匹配我要睡觉之前的头位置,最后的匹配结果只是"我要下班~"。 negative_lookahead_regex = 我要下班3~(?!我要睡觉)
// 这里的含义为 匹配"我要下班3"这个模式,然后匹配 不满足"我要睡觉"这个模式的头位置。 最后的匹配结果只是"我要下班3"。 positive_lookbehind_regex = (?<=我要吃好吃的~)我要下班 negative_lookbehind_regex = (?<!我要吃好吃的~)我要下班

   快速记忆方法:

  1、首先(? 开头 表示非捕获组

  2、然后如果是负向的断言 则会跟 "<"

  3、最后 肯定 是"=",否定是"!"

  Q:  正向  肯定 预查    equals      (?=pattern)

             负向  否定 预查    equals      (?<!pattern)

 

四、实践中不断理解

str1 = "123456789 12384"
pattern = \B(?=(?:\d{3})+(?!\d))

Q:如果用这个模式去 匹配str1,并且对匹配到的位置进行替换成","
最终结果会是什么,这个过程是怎样的?

最好自己有答案,在看结果哦~

str1 = "123456789 12384"
pattern = "/\B(?=(?:\d{3})+(?!\d))/g"
str1.replace(pattern,',')


// "123,456,789 12,384"
View Code

 

posted @ 2020-09-24 23:48  itsmisa  阅读(510)  评论(0)    收藏  举报