李恒道 发表于 2022-5-19 01:27:58

正则表达式(?=.*[a-z])含义

# Tips
3楼有cxxjackie的理解
非常清晰易懂并且薛劈入里!
推荐大家详细品读
# 开篇
最近在学习正则的时候
突然发现好多常见的正则表达式
大家都在用,但是他妈的又是根本查不到中文资料....
不知道为啥感觉中文编程环境随便一点基础问题资料缺乏的要命
要不我好好学习正则再建个正则中文网吧(笑
今天突然很好奇(?=.\*)的意思
(?=xxx)实际是一个环视断言语句
?=是向后查找字符串

我爱你 我爱他
我爱(?=你)
这个时候只能检索到我爱你
这种格式是
表达式1(表达式2)
那问题来了
(?=. \*)通常都是放在前边是怎么执行的?!
这个问题我查了一晚上才搞明白
大家可以参考
https://stackoverflow.com/questions/2973436/regex-lookahead-lookbehind-and-atomic-groups
我大概重述一下
# 理论
环视是一个零宽度断言,他们会检查正则表达式,在找到匹配的时候判断成功或失败来决定是否抛弃内容,同时它不消耗任何字符,后续的正则表达式会从相同的字符位置继续执行
详情可以阅读
http://www.regular-expressions.info/lookaround.html

(?=表达式1)表达式2
当表达式1匹配成功的时候,会从相同位置匹配表达式2
那么我们现在再来看
我爱(?=你)
当匹配我爱你的时候
首先找到我爱,然后发现环视表达式,看后方存在你,于是匹配成功
而匹配我爱他的时候
找到我爱后,发现后放不存在你,于是匹配失败。
而假设我们调换顺序呢?

(?=你)我爱
这个表达式是否成立?
大家可以开动你的小脑筋想一想
当然成立!个鬼啦!怎么可能成立
假设我们写一个你我爱
首先找到环视表达式(?=你)
找到了你字,然后保持原位置不变,开始搜寻我爱
因为第一个字匹配成功,一定是一个你,所以不可能匹配上我爱
也就是说这是一个失败的正则表达式
那我们怎么改?
(?=你)你我爱
用来搜寻字符 【你我爱你】
这样的表达式是成功的
因为第一个字匹配成功,是一个你,然后原位置搜寻你我爱
我们的字符是匹配的,所以匹配成功!
那么接下来我们看正则表达式
(?=.\*)
.\*代表匹配任意字符0至任意一个宽度
而a-z代表匹配一个小写字符a-z的任何一个
一旦找到了小写字母,则认为表达式是成立的
然后继续往后进行匹配
那我们看一个比较长的表达式
![图片.png](data/attachment/forum/202205/19/012620ou8zxyhxuue8hfro.png)
.\*?这里的?代表是非贪婪模式
第一个正则表达式搜寻是否存在小写字母
第二个正则表达式搜寻是否存在大写字母
而两个都成功
则在原位置匹配字符了
如果你看到这里相信你应该明白了环视表达式的计算方式了!
# 结语
撒花~


15533829110 发表于 2022-5-19 10:00:28

正则表达式常用的规则如下:
^:表示开始
$:表示结束
[ ]:代表某个范围内的单个字符,比如: 单个数字字符
.:代表任意单个字符,除了换行和行结束符
\w:代表单词字符:字母、数字、下划线(),相当于
\d:代表数字字符: 相当于
量词:
+:至少一个
*:零个或多个
?:零个或一个
{x}:x个
{m,}:至少m个
{m,n}:至少m个,最多n个

cxxjackie 发表于 2022-5-19 11:41:20

我的理解是?=表达的是位置,即从字符串的某个位置开始匹配。先理解?<=,/(?<=a)bc/会首先找到a,然后以a为起点(不包括a)向后查找bc,换句话说,就是匹配以a开头的bc字符串,不包括a。?=非常相似,只是方向改成向前,/ab(?=c)/匹配以c结尾的ab字符串,不包括c。这主要涉及正则的捕获组,可以使某些字符串既在规则里,又不被捕获到,这在截取某些特征字符时比较有用,比如一段html,截取某个元素的文本,可以写成:/(?<=<div id="test">).*?(?=<\/div>)/。另一组语法是?<!和?!,是上面语法的否定,可以简单理解为匹配不以某字符串开头/结尾的字符串。
为什么说这些语法表达的是位置,当整段表达式都用?=括起来时,匹配结果会是空字符,这个空字符其实就表示了位置。js的replace函数,可以利用这个位置插入字符,参考以下例子来理解:
'abc'.replace(/(?<=b)/, 'd') //abdc
'abc'.replace(/(?=b)/, 'd') //adbc
?=是向前查找,一般放在表达式的后面,如果放在最前面,由于往前没有表达式,所以会先停到对应的位置,再开始向后匹配,比如:
'abc'.match(/(?=b).*/)
首先(?=b)会停在a和bc之间的位置,往后.*,结果匹配bc。值得注意的是,将?=前置很多时候是没有意义的,上面的正则可以直接改成/b.*/,类似于/(?=a)abc/这样的写法完全是废话。将?<=后置与这一情况类似。
关于捕获组的概念,正则可以通过加括号来给结果分组,像match函数的结果就是一个数组,上面html的例子可以改写成:
str.match(/<div id="test">(.*?)<\/div>/)
这种情况不需要用到?<=、?=,不分组的情况下这些语法才更有价值。比如一些文本工具(包括浏览器的F12)提供正则搜索,这种场景显然是不分组的,假设我们要在某段代码中搜索变量i,但i也可能夹杂在一串单词中间,可以写成:/(?<=\W)i(?=\W)/或/(?<!\w)i(?!\w)/

水凛子 发表于 2022-5-19 09:59:18

泻药,已经不认识`你`字了

李恒道 发表于 2022-5-19 10:16:09

水凛子 发表于 2022-5-19 09:59
泻药,已经不认识`你`字了

你不知道的船新版本

李恒道 发表于 2022-5-19 10:16:26

15533829110 发表于 2022-5-19 10:00
正则表达式常用的规则如下:
^:表示开始
$:表示结束


正则写着太累了...
呜呜呜
每次写正则跟做高数一样

李恒道 发表于 2022-5-19 14:53:41

cxxjackie 发表于 2022-5-19 11:41
我的理解是?=表达的是位置,即从字符串的某个位置开始匹配。先理解?

读了好几遍
如果早看到估计直接就明白了
不用那么费劲找资料了...呜呜呜
哥哥讲的比市面上的正则教程清晰多了
对环视的理解加强了!

airbeyond 发表于 2022-5-20 08:44:36

推荐好用的一个正则测试和调试的网站 https://regex101.com/

李恒道 发表于 2022-5-20 09:17:25

airbeyond 发表于 2022-5-20 08:44
推荐好用的一个正则测试和调试的网站 https://regex101.com/

这个确实好用!

steven026 发表于 2022-7-2 17:43:47

之前在其他地方看到一个很有意思的正则,至今还是没看懂,
需求:将一个字符串按3位数为1组切割
比如"aaabbbcccdddeeefffggghh"
我的写法是,直接用match匹配3个字符,如果字符串长度不是3的倍数那么会剩余1\~2个字符再通过字符串结尾匹配就行了

```
> "aaabbbcccdddeeefffggghh".match(/.{3}|.{1,2}$/g)
< (8) ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg', 'hh']
```

别人的写法是直接split 3个字符后面的""空字符(至今没看懂这是怎么匹配上的)

```
> "aaabbbcccdddeeefffggghh".split(/(?<=^(?:...)*)/)
< (8) ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg', 'hh']
```

虽然殊途同归,但我还是想弄清楚这个原理,不知道GG有什么见解?
页: [1] 2
查看完整版本: 正则表达式(?=.*[a-z])含义