马黑黑 发表于 2023-1-15 22:34

正则表达式之正向先行断言

<style>
#mydiv { #with: 600px; }
#mydiv >p { margin: 10px 0; padding: 0; }
</style>

<h2>正则表达式:正向先行断言(演示)</h2>
<div id="mydiv">
        <p>Windows95</p>
        <p>Windows 95</p>
        <p>Windows98</p>
        <p>Windows 98</p>
        <p>WindowsME</p>
        <p>Windows ME</p>
        <p>Windows2000</p>
        <p>Windows 2000</p>
        <p>WindowsXP</p>
        <p>Windows XP</p>
        <p>Windows7</p>
        <p>Windows 7</p>
        <p>Windows10</p>
        <p>Windows 10</p>
                <p>Windows11</p>
        <p>Windows 11</p>
</div>
<p><button id="btn" type="button">Okey</button> <input id="pipei" type="text" value="Windows(?=95)"/></p>

<script>

btn.onclick = () => {
        let str = mydiv.innerHTML;
        str = str.replace(/<\/?span[^>]*>/g,''); //去除 span 标签
        let reg = new RegExp(pipei.value.trim(), 'g');
        let ar = str.match(reg);
        if (ar) {
                mydiv.innerHTML = str.replace(reg,'<span style="color: red">$&</span>');
        }
}

</script>

马黑黑 发表于 2023-1-15 22:35

正则非捕获匹配 - 正向先行断言

表达式(?=子表达式)

例:

Windows(?=95)

Windows 是表达式,是我们要查找的核心,也就是我们要匹配的“Windows”,但不是所有的“Windows”都会匹配,它由子表达式 ?=95 决定,子表达式中的 ?= 引出的子表达式是 95,它限制了前面的“Windows”后面必须紧跟着“95”才能匹配,“Windows98”和“Windows7”中的“Windows”都不匹配。需要注意的是,通过匹配得到结果的仅仅是“Windows”,不包含子表达式中的 95,因此断言又称为“零宽断言”,子表达式在匹配过程中只起限制作用,不占存储字符,术语称之为不消耗。

总得来讲,正向先行断言是要去匹配一个主表达式,该表达式后面跟着一个子表达式,子表达式用于限制主表达式的匹配条件,子表达式由 ?= 做引导,子表达式只做限制匹配条件,不参与将来的匹配结果的引用,如果匹配成立那么整个正则表达式匹配出的结果就是主表达式自身。

主表达式和子表达式可以是字面词,也可以是各种规则的正则表达式。

先说主表达式。Windows95 也可以写成为 Windows 95,Windows 和 95 之间可以有一个空格,那么,我们想两种表示法都匹配,就改造主表达式的构造:

Windows\s?

其中,\s 是空格,? 是正则量词,表示0或1次。合起来,主表达式的意思就是 Windows后面或者有一个空格或者没有。这样处理后,Windows95 和 Windows 95 中的 Windows 都会被匹配到。

接着改造子表达式。我们希望能同时匹配 Windows95/98/XP/7,子表达式可以这么写,(?=95|98|XP|7),其中,符号 | 表示或者的意思。连同改写过的主表达式,正则式子是这样:

Windows\s?(?=95|98|XP|7)

这个表达式就能匹配主表达式和子表达式共同营造的条件,演示框中对应项的 Windows 都会被标红。

还可以针对主、子表达式做更复杂的操作,这里就点到为止了。

红影 发表于 2023-1-15 22:49

我用Windows\s?去试,结果全亮了{:4_173:}

红影 发表于 2023-1-15 22:51

Windows\s95?去选,亮了两个。Windows 95和Windows 98 ,不懂,为什么加了数字就必须有空格了。

马黑黑 发表于 2023-1-16 10:56

红影 发表于 2023-1-15 22:49
我用Windows\s?去试,结果全亮了

Windows\s?,表示匹配 Windows 加 空格有无均可,它能匹配:
Windows
Windows


文本着色体现不出来,加背景色的话,匹配情形会如上所示。

马黑黑 发表于 2023-1-16 11:02

红影 发表于 2023-1-15 22:51
Windows\s95?去选,亮了两个。Windows 95和Windows 98 ,不懂,为什么加了数字就必须有空格了。

你的表达式:

Windows\s95?

表示,去匹配——

Windows空格9可有可无的5(5? ,5跟一个问号,表示5可以是出现0次或1次)

这样,能匹配的是:

Windows 95
Windows 9

你尝试去匹配的,都与本帖讨论的先行断言无关。

红影 发表于 2023-1-16 16:21

马黑黑 发表于 2023-1-16 10:56
Windows\s?,表示匹配 Windows 加 空格有无均可,它能匹配:
Windows
Windows

这个范围倒是大呢。

红影 发表于 2023-1-16 16:22

马黑黑 发表于 2023-1-16 11:02
你的表达式:

Windows\s95?


哦哦,先行断言几个字挺难理解的。

马黑黑 发表于 2023-1-16 16:57

红影 发表于 2023-1-16 16:22
哦哦,先行断言几个字挺难理解的。

关于断言,其实网上的解释有两种绝然相反的观点。我个人倾向于这么理解(也根据英文描述):

先行断言,子表达式在后面限制前面的主表达式:主表达式(?=子表达式) 或 主表达式(?!子表达式)

后行断言,子表达式在前面限制其后面的主表达式:(?<=子表达式)主表达式"> 或 (?<!子表达式)主表达式">

理解起来,就是,子表达式限制前面的内容,就叫先行断言,子表达式限制后面的内容,就叫后行断言。

马黑黑 发表于 2023-1-16 16:58

红影 发表于 2023-1-16 16:21
这个范围倒是大呢。

我这个帖子的示例,是用来演示正向先行断言的,但程序支持匹配任何正则,包括纯字面量。

红影 发表于 2023-1-16 18:35

马黑黑 发表于 2023-1-16 16:57
关于断言,其实网上的解释有两种绝然相反的观点。我个人倾向于这么理解(也根据英文描述):

先行断言 ...

原来是和后行断言相对而已言的,这名称怪怪的,不过适应了就好{:4_173:}

红影 发表于 2023-1-16 18:37

马黑黑 发表于 2023-1-16 16:58
我这个帖子的示例,是用来演示正向先行断言的,但程序支持匹配任何正则,包括纯字面量。

断言分先行后行,还分正向负向,真是够晕的{:4_173:}

马黑黑 发表于 2023-1-16 18:56

红影 发表于 2023-1-16 18:37
断言分先行后行,还分正向负向,真是够晕的

是的。正向负向其实就是肯定否定

马黑黑 发表于 2023-1-16 18:57

红影 发表于 2023-1-16 18:35
原来是和后行断言相对而已言的,这名称怪怪的,不过适应了就好

最初,我也困惑,后来看了英文文档,借助翻译机,弄明白了

红影 发表于 2023-1-16 21:04

马黑黑 发表于 2023-1-16 18:56
是的。正向负向其实就是肯定否定

还是肯定否定的说法更容易理解。

红影 发表于 2023-1-16 21:06

马黑黑 发表于 2023-1-16 18:57
最初,我也困惑,后来看了英文文档,借助翻译机,弄明白了

你对这个有兴趣,还愿意自己去看看,很多不是这个行当的人看到的时候肯定晕乎乎{:4_173:}

马黑黑 发表于 2023-1-16 21:07

红影 发表于 2023-1-16 21:06
你对这个有兴趣,还愿意自己去看看,很多不是这个行当的人看到的时候肯定晕乎乎

个人所好吧

马黑黑 发表于 2023-1-16 21:07

红影 发表于 2023-1-16 21:04
还是肯定否定的说法更容易理解。

差不多的

红影 发表于 2023-1-16 21:42

马黑黑 发表于 2023-1-16 21:07
个人所好吧

而且是很有成绩的喜好{:4_187:}

红影 发表于 2023-1-16 21:42

马黑黑 发表于 2023-1-16 21:07
差不多的

嗯嗯,习惯后,不管是什么名字,都知道所指了。
页: [1] 2 3
查看完整版本: 正则表达式之正向先行断言