正则表达式的用处真的很多很多。可以用来验证字段,批量处理文件内容,快速查询想要的信息,处理数据为自己想要的样子。
感觉非常的好用和有用。无论是前端后端,运维等等都离不开正则表达式。它可以让我们很多的工作事半功倍,而且减少很多代码量。
好,说了那么多。但是我这里并不介绍正则表达式的基本的几个东西的表达。我主要讲一个符号。就是?
因为这个符号(?)真的比较难理解啊,官方的解释也不是很好懂。我也是反复看了多次才最终把他了解下来。
那么现在我就结合实际例子开始来解释一下这个?的含义。
?
只有这个符号(?)的时候,表示的是0个或1个。相当于{0,1}。好的这个就不多解释了。
?开头的组合
这种问号开头的,它一定是有圆括号包住的它的如 (?:)
?:
这个组合(?:)其实加了和没加都是一个意思。不会影响正则表达式的原本意思。
你肯定有疑问,那为什么要有这个组合?
它还是有用的。因为正则里面加了括号都会被认为是一组数据。
举个栗子:
1 | 'a,b'.replace(/^(\w+),(\w+)$/,'$2,$1') |
这个得到的结果就是b,a
这里面后面的$1,$2代表的就是就是你前面的括号表示的组合,$1是逗号前面的那个括号匹配到的组合,$2就是逗号后面的括号匹配到的组合。
然后替换的时候修改两者的顺序,从而达到交换位置的效果。
好,讲完上面的。回到刚刚的问题,那么为什么要加 (?:) 呢?就是你这里需要加括号但是不希望它成为一个组合,那么就可以加。
如果上面的表达式,逗号那里不得不加括号,如果直接加,那$2就会变成逗号,匹配逗号后面的组合就变成$3了 。这时候我不希望逗号成为一个组合。
1 | 'a,b'.replace(/^(\w+)(?:,)(\w+)$/,'$2,$1') |
这样的话又可以即使用逗号,后面的$2也不会变成匹配到逗号。
注意:字符串这里的替换使用的是$1,$2…,正则表达式里面使用的话是\1,\2…
正则里面使用组合的栗子:
匹配重叠两个连续的重复单词
1 | /^(\w+)\1$/.test('hellohello') //true |
?= 和 ?<=
前面真的扯太多了,后面我加快进度讲。
同样的只要加了问号在前面的组合,这种都会被认为是不需要组合的,只是说 (?:) 没有别的特殊含义,别的组合还是有各自的含义的。
如 (?=bean) 表示匹配以bean结尾的前面部分(匹配到的内容不包含bean),一般是加在所要匹配内容的后面。
(/\b\w+(?=bean\b)/)
而 (?<=bean) 表示匹配以bean结尾的后面部分(匹配到的内容不包含bean),一般是加在所要匹配的内容前面。
((?<=\bbean)\w+\b)/)
实例栗子:比如你要批量修改一篇文章中的出现的“编辑文章”,“编辑数据”改成“修改文章”,“修改数据”。
那么我们可以这么写。假设str是文章的内容字符串。
1 | str.replace(/编辑(?=(文章|数据))/g,'修改') |
这个例子就是匹配以“文章”或“数据”开头带有“编辑”的文字,把它替换成“修改”。
以前我一直不知道为什么要存在这样的一个判断。我都知道我要匹配的是“编辑”了,为什么还要去匹配?原因就在于我们需要去批量替换符合条件的统一数据。就想我要改变的是“文章”或“数据”前面的“编辑”文字,别的“编辑”我都不需要换。这就是这些正则的价值了。
其实不只是js替换使用,其实很多时候我们项目中的一些文案需要统一改是,我们也可以使用sublime来写正则表达式全局替换。
?! 和 ?<!
有了前面的铺垫,同理这两个字符解释起来就很简单了。
(?!bean) 就是匹配后面不跟“bean”的。
(?>!bean) 就是匹配前面不跟“bean”的。
这种正则表达式就可以处理,非的条件比较确定的。
比如我除了需要“编辑文章”和“编辑数据”不需要改成“修改文章”和“修改数据”,其他都要改成“修改”。这就可以使用了。
这里就不再贴例子了。
?结尾的组合
问号结尾的组合一般指的就是懒惰的正则语法了。
贪婪和懒惰只是一种形象的形容。贪婪就是匹配的越多越好,懒惰就是匹配到的越少越好。
一般不加问号的,+和*默认都是贪婪匹配,加了?后就变成了越少越好。这样说还是挺抽象的。下面来一个个说。
+? 和 *?
+? 重复1次或更多次,但尽可能少重复
*? 是匹配重复任意次,但尽可能少重复
就比如说刚刚的例子。我需要把“编辑”改成“修改”。但是后面跟着字我们不去限制。只是简单的写如下的正则去匹配替换
举个栗子:如果有这样的一个字符串”编辑文章编辑数据”
1 | "编辑文章编辑数据".replace(/编辑([\u4e00-\u9fa5]+)/g,'修改$1'); // 结果:"修改文章编辑数据" |
ps: [\u4e00-\u9fa5]代表在中文字,是中文字符的范围。
为什么结果会这样的。首先因为默认是贪婪匹配,所以会匹配到最长的组合$1就是”文章编辑数据”,就变成了”修改文章编辑数据”,后面的那个编辑就没有修改过来了。
如果这样:
1 | "编辑文章编辑数据".replace(/编辑([\u4e00-\u9fa5]+?)/g,'修改$1'); // 结果:"修改文章修改数据" |
这样,它就会尽可能地匹配更少的,所以它会匹配的两个,一个是“编辑文”,一个是“编辑数”,然后把他们都修改成“修改文”和“修改数”
所以结果就变成了“修改文章修改数据”。我不知道我的栗子取得恰不恰当。但是一般这种的话会限制头和尾,这样的匹配会更加精准。
如:a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
?? , {n,m}? 和 {n,}?
剩下就很好理解了
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
好的,一笔带过。
总结
至此,我就把正则的?的所有可能的情况都介绍了一下。这也是我的一些见解。很多网上的资料和官方文档我觉得都讲得很好,但是不是很好理解。
希望我的解释大家能懂。这也是我自己的一个理解写出来的东西。如果文章有什么问题和错误,可以邮箱告诉我的。