1、为了切入这个问题,首先介绍一下问题背景:

下面为示例文本
[color1]
red
blue
[color2]
blue
black
2、问题来了
现在我要匹配 [color1] 所在分组的内容,按照下面的正则表达式写法
\[color1\]([\S\s](?!\n[\s]*\[))*
上面正则的图形化表示如下图

上面的正则看起来是没问题了,看下匹配的结果吧(竟然出错了)

3、看下相对正确的正则表达式
\[color1\](?:(?!\n[\s]*\[)[\S\s])*
先看这个正则的图形化表示(注意和上一个差别在哪里,位置调换了)

再看匹配结果(竟然匹配成功了)

4、问题分析(已解决)
- 所以为什么两种正则匹配的方法,后一种只是把匹配的顺序调换了,就可以匹配成功呢?
如果使用正则1:
([\S\s](?!\n[\s]*\[))*
其中 [\S\s] 中的 \s 表示空白符号,即包括空格、换行、tab缩进等所有空白字符,而 \S 与 \s 相反表示所有非空白字符,[\S\s] 组合即可匹配所有字符
其中 (?!pattern) 意思为:在任何不匹配pattern的字符串开始处匹配查找字符串,则这里表示从不是
\n[\s]*\[ 这些字符的地方开始匹配,\n[\s]*\[ 表示的意思为 一个换行紧跟若干个空格之后紧跟一个 [
而我们的待匹配字符串是这样:
...
blue
[color2]
.....
现在跟随它的匹配流程,它匹配到 ue 的时候 u 满足 [\S\s],e 满足 (?!\n[\s]*\[),这时继续向下走,
遇到 e\n,但是此时 e 满足 [\S\s],但是 \n 不满足 (?!\n[\s]*\[),这个时候需要进行回退,选择满足条件的 ue,而模式 ______(?!xxx) 匹配的是下划线中的内容,当符合 (?!xxx) 时候 xxx 被抛弃不作为匹配结果,这就解释了为什么 e 作为最后一个可见字符被抛弃
如果使用正则2:
\[color1\](?:(?!\n[\s]*\[)[\S\s])*
上面的正则可以写作下面的形式
(\[.*?\])((?!\n\s*\[)[\s\S])*
为了使他更简单,我将 ?: 但是他的匹配功能还是不变的,区别就是 (?:pattern) 只匹配 pattern 但是不获取匹配结果
这次 [\s\S] 与 (?!\n\s*\[) 的顺序正相反,现在跟随它的匹配过程,
...
blue
[color2]
.....
假设匹配到了 ue,u 满足不跟随 (\n\s*\[) ,u也满足跟随 [\s\S]* ,e也相同。现在匹配 e\n,e 满足不跟随 (\n\s*\[), e 满足 [\s\S],\n 不满足不跟随 (\n\s*\[),因此回退到 ue 同时抛弃 \n
原创文章,作者:witersen,如若转载,请注明出处:https://www.witersen.com