前言

本文介绍一些正则中的常用名词以及对应概念,譬如字符组,捕获组、非捕获组、反向引用、转义和\s \b

大纲

  • 字符组
  • 捕获组
  • 反向引用
  • 非捕获组
  • .\s\S
  • \b
  • \转义

字符组

[]字符组表示在同一个位置可能出现的各种字符,也就是说它的匹配结果只能是一个字符,不能是多个

例如[hello]匹配的不是hello而是h或e或l或o

特点

  • 结果只会匹配一个字符
  • 内部特殊字符无需转义\ [ ] 除外

    • 另外,^出现在最开始位置时需要转义
    • -前后构成区间范围时需要转义(推荐永远使用转义\-
  • -表示连字符
  • ^表示排除符

示例

特殊字符无需转义

[\^*\-+|(a)]

这个示例的含义是,匹配以下字符中的任意一个

  • ^ * - + | ( a )
  • 可以看到,这些特殊字符在字符组中仅仅就是字符本身

连字符的作用

[z-a]

匹配这个正则表达式会报错(Range out of order in character class

原因是连字符后面的字符码要大于等于前面的字符码

var str = 'abc-';
var reg = /[a-z-]/g;// 最后的连字符没有构成区间,所以仅仅表示  - 这个字符
str.match(reg); // ["a", "b", "c", "-"]
var str = "aAbc-";
var reg = /[A-a-z]/g;// 通用,A-a 构成一个区间  之后的 -z 无法构成区间,于是它只能作为-字符本身
str.match(reg); // ["a", "A", "-"]

排除型

var str = '01ABabc-';
var reg = /[^a-z]/g;// 匹配了除a-z范围外的任意字符
str.match(reg); // ["0", "1", "A", "B", "-"]

排除型字符组用法和普通的一样,但是唯一区别是

  • 排除型代表符合条件的都不匹配(功能相反)

\b特殊情况

var str = 'ab\bd,cdef';
var reg = /[\b]/g;
var reg2 =  /\bc/g;
var reg3 =  /[\b]c/g; str.match(reg); // [""] 匹配\b本身
str.match(reg2); // ["c"]  即匹配,号后面的c
str.match(reg3); // null 因为\b后面没有c
  • \b在字符组以外表示单词边界
  • 在字符组内,表示退格符(\b)

捕获组

捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用

例如: /(a)(b)(c)/中的捕获组编号为

  • 0: abc
  • 1: a
  • 2: b
  • 3: c

其中,组0是正则表达式整体匹配结果,组1`2`3才是子表达式匹配结果

特点

  • 子表达式捕获组编号从1开始,顺序从左到右(例如编号1是左侧第一个()包裹的子表达式的结果)
  • 可以在正则表达式中对前面捕获的内容进行引用(反向引用)
  • 也可以在程序中,对捕获组捕获的内容进行引用(比如replace中)

示例

子表达式捕获组编号从1开始,顺序从左到右

var str = "2017-07-29";
var reg = /(\d{4})-(\d{2})-(\d{2})/;// 非全局模式有捕获组结果
str.match(reg); // ["2017-07-29", "2017", "07", "29", index: 0, input: "2017-07-29"]

上述匹配中,除了整个正则表达式的结果外,还有各个捕获组的结果,其中,子表达式的捕获组从编号1开始,如下

编号 捕获组 匹配内容
0 (d{4})-(d{2})-(d{2}) 2017-07-29
1 d{4} 2017
2 d{2} 07
3 d{2} 29

JS程序内的引用

  • replace中,JS通过$number引用捕获组内容
  • 在外部匹配引用,JS通过RegExp.$number引用捕获组内容
var str = '<div id="code1" class="highlight"></div>';
var reg = /<(\w+)[^>]*>/g;// <div></div>
str = str.replace(reg, "<$1>");

可以看到,在去除div中的属性时,先是整个匹配<divxxx>,然后再把整个内容替换成<$1>,其中$1就是第一个捕获组结果div的引用

注,请不要引用$0,因为它不属于子表达式的捕获组,在replace中引用$0没有任何效果

var str = 'abcd0123ABCD';
var reg = /([a-z]+)(\d+)([A-Z]+)/g;reg.test(str); // trueconsole.log(RegExp.$0); // undefined
console.log(RegExp.$1); // abcd
console.log(RegExp.$2); // 0123
console.log(RegExp.$3); // ABCD

注,同样$0的引用没有内容

反向引用

在正则表达式内部对捕获组进行引用称之为反向引用

var str = "boom==boom";
var reg = /(boom)==\1/;str.match(reg); // ["boom==boom", "boom", index: 0, input: "boom==boom"]

可以看到,正则中\1的值就是捕获组1匹配到的结果boom

因此,这个表达式等价于(boom)==boom

示例

var str = '1234567899';
var str2 = '12345678999';var reg = /^(?:([0-9])(?!\1{2})){1,}$/;reg.test(str); // true
reg.test(str2); // false

上例中的效果是,匹配一个数字,但是数字中不允许连续出现3次以上的重复数字

  • 用到反向引用可以很好的实现

非捕获组

上述可以看到()包括的内容默认匹配时都在捕获组中

但是有时候,因为特殊原因用到了(),但又没有引用它的必要,这时候就可以用非捕获组声明,防止它作为捕获组,降低内存浪费

  • ?:可以声明一个子表达式为非捕获组
var str = 'abcd0123ABCD';
var reg = /(?:[a-z]+)(\d+)([A-Z]+)/g;reg.test(str); // trueconsole.log(RegExp.$0); // undefined
console.log(RegExp.$1); // 0123
console.log(RegExp.$2); // ABCD

可以看到,(?:[a-z]+)将这个子表达式声明成了非捕获组,因此捕获组的编号直接跳过了它,从下一个(\d+)开始

.\s\S

首先说下.

  • 定义是除\n以外的任何字符
  • 但是,在一些ChromeFirefox等内核中,代表\n\r以外的字符
  • 如果要匹配.本身,请用\.

再说说\s\S

  • \s是匹配所有的空白字符,包括空白换行tab缩进等所有空白
  • \S是指除了空白以外的任何字符(和.区别下,.里面还多了一部分空白)

那如何匹配所有字符呢?

  • (.|\n)或者是[\s\S](推荐用法)
  • 请不要试图使用[.\n][\.\n],这种写法只表示小数点或\n字符中的一个

示例

请写一个表达式,去除多行注释

var str = '\var a = 1; \r\n\/\** \r\n\* 这里是注释 \r\n\*/\r\n\var b = 2;\r\n\console.log(a)';var reg = xxx;str = str.replace(reg, '');

解答

var reg = /\/\*{1,}[\s\S]*\*\//g;

这里就用的了用[\s\S]来匹配所有的字符(因为仅仅是.是无法匹配\r\n的)

\b 单词边界

\b匹配单词边界,不匹配任何字符

简单的说,\b匹配的位置,一侧是构成单词的字符,另一侧是非单词字符,字符串的开始或结束

而其中单词的判断就是\w的匹配范围(正常a-zA-Z0-9_JS举例)

注,有一特例,在字符组中[\b]表示的是退格符

特点

  • 零宽,即匹配的是位置而不是字符
  • \w来界定单词
  • 字符组中是退格符的意思

示例

var str = 'abc_d=efg+hij哈opq%';var reg = /.\b./g;// ["d=", "g+", "j哈", "q%"]
str.match(reg);

可以看到,分别在如下几处有单词分界

  • d=直接有一个分界
  • g+之间
  • j
  • q%

\转义

var str = 'ab\\cd'; // 字符串 ab\cd
var str2 = 'ab\\\\cd'; // 字符串 ab\\cdvar reg = /ab\\\\cd/;
var reg2 = new RegExp('ab\\\\cd');reg.test(str); // false
reg.test(str2); // truereg2.test(str); // true
reg2.test(str2); // false

出现\的地方,得多加注意,需要梳理清楚转义逻辑,通过上例可以看到,在正则中出现的\和在字符串中出现的\意义不一样

  • reg中,\出现在正则中,所以\\\\的意思就是匹配\\字符串,所以测试str2通过,str失败
  • reg2中,\出现在字符串中,所以\\\\的意思\\,然后构建为正则表达式,最终在正则中是\\,也就是匹配\字符串本身,所以测试str通过,str2失败

附录

博客

初次发布2017.07.31于个人博客

http://www.dailichun.com/2017/08/01/regularExpressionConcepts.html

参考资料

  • 正则表达式元字符
  • 正则表达式基础系列博客

【正则表达式系列】一些概念(字符组、捕获组、非捕获组)相关推荐

  1. 计算机电源MOD,模组电源和非模组区别是什么?电脑电源的工作原理是什么?

    很多人在组装电脑的时候电源只看功率,只要功率够用就行了,其实电源除了看品牌看功率外还有个非常重要一点的就是这个电源是模组的还是非模组的,它们之间的差别还是挺大的,很多人不理解电源还要分模组和非模组组? ...

  2. 第5章_使用者(User)_群组(Group)_非群组外的其他人(Other)文件权限改变

    1. Linux用户身份与群组相关信息 系统上账号信息 个人密码记录在/etc/shadow文件中 Linux中的组名记录在/etc/group 通过ls -al 查看文件权限,可以分别看到 文件所有 ...

  3. lambda捕获this_非捕获Lambda的实例

    lambda捕获this 大约一个月前,我在Java 8的lambda表达式框架下总结了Brian Goetz的观点 . 目前,我正在研究有关默认方法的文章,令我惊讶的是,我又回到了Java处理lam ...

  4. 正则表达式中的非捕获组是什么?

    非捕获组(即(?:) )如何在正则表达式中使用,它们有什么用? #1楼 在复杂的正则表达式中,您可能会希望使用大量的组,其中一些用于重复匹配,而另一些则提供反向引用. 默认情况下,与每个组匹配的文本会 ...

  5. 正则表达式 —— 非捕获元

    非捕获元讲解 正则表达式语法中,有一种称为"非捕获元".是基于子表达式的语法规则: 举例1 (pattern) 匹配 pattern 并获取这一匹配.所获取的匹配可以从产生的 Ma ...

  6. 计算机主机电源是否都一样,电脑主机电源全模组和非模组有什么不同,到底该怎么选?...

    原标题:电脑主机电源全模组和非模组有什么不同,到底该怎么选? 一台电脑能不能发挥它的极限性能,关键是要看电源.俗话说得好酒足饭饱好做事.一台电脑无论配置高低,都需要有充足的电力才能有高的性能动力.如果 ...

  7. java正则表达式基础 关于特殊字符、捕获组和非捕获匹配

    JAVA正则表达式 我个人认为正则表达式是很好用很强大的,在编写程序中很多地方都用的到,这里有一些我学习的基础理解和大家分享,欢迎一起讨论. 正则表达式是一种用来表达语法规则的字符串,是一种字符串匹配 ...

  8. 正则表达式之非捕获组

    有什么用 非捕获类,在正则很简单时,没什么用,只有在正则中大量使用()时才有用 详细说明-举例说明 匹配2013-05-07,你可以用\d{4}-\d{2}-\d{2},你也可以加个括号(\d{4}) ...

  9. 【整理】Python中的re.search和re.findall之间的区别和联系 + re.finall中带命名的组,不带命名的组,非捕获的组,没有分组四种类型之间的区别

    之前自己曾被搞晕过很多次. 后来使用这些函数次数多了之后,终于比较清楚的弄懂了两者之间的区别和关系了. 尤其是一些细节方面的注意事项了. 在看下面的总结和代码之前,请先确保你对如下基本概念已经有所了解 ...

最新文章

  1. Genome-scale de novo assembly using ALGA 使用ALGA进行 基因组规模的从头组装
  2. 5G 标准 — 3GPP
  3. Struts(八)Strits2访问servlet API
  4. Istio入门:架构原理及在k8s部署
  5. numpy.loadtxt()用法
  6. Spark 运行模式 standalong yarn
  7. 使用idea工具运行第一个spring boot项目
  8. Mysql插入锁表情况
  9. Design Pattern 设计模式【观察者】
  10. RK3288_Android7.1调试RTC总结(一)
  11. 差分进化算法和遗传算法 区别 谁更好
  12. springboot 银联支付(扫码支付)
  13. [NLP]OpenNLP词性标注器的使用
  14. 谷歌图形化HTML5网页编辑器Google Web Designer
  15. 群晖Docker百度网盘套件一直灰界面
  16. 西电微机系统课程设计步进电机开环控制系统
  17. 中文版ASAM OpenSCENARIO 1.0标准解读
  18. TV(智能电视)app开发,电视wifi连接Android studio 真机调试
  19. 画中画 视频叠加 视频覆盖 overlay
  20. 解决上网认证系统 IP 更改后 Ubuntu 等 Linux 系统无法上网的问题

热门文章

  1. 一切都是问题,一切都着落在自身
  2. [建筑可视化]Evermotion-Archinteriors for UE4
  3. python中词云图是用来描述_Python制作词云图代码实例
  4. 2000亿次开放学习后,DeepMind的智能体成精了
  5. 谷歌程序员少输一个“”,差点让全球Chrome笔记本变砖
  6. Jupyter Notebook已出现“返祖现象”,这款工具让你在终端里使用它
  7. 马斯克的火箭,这次没!爆!炸!
  8. 华为开源自研AI框架MindSpore!自动微分、并行加持,一次训练,可多场景部署...
  9. 9岁去读博!全球最年轻的大学毕业生火了:4岁上小学,8岁进入荷兰“中科大”,智商145...
  10. 脑机接口创造“第六感”:激活特定神经元,大鼠训练出新感官,逃出水迷宫,像用视觉一样轻松...