感谢本文参考《正则表达式迷你书》分组和分支结构分组括号可以提供分组的功能。/a+/, 标示a出现多次。/(ab)+/, 则是将ab作为一组,表示ab出现多次。分组引用使用括号可以实现数据提取和替换操作。我们以匹配日期(yyyy-mm-dd)为例// 无括号版本var reg1 = /\d{4}-\d{2}-\d{2}/// 有括号版本var reg2 = /(\d{4})-(\d{2})-(\d{2})/正则引擎在匹配的过程中,会存储每一个分组匹配到的数据提取分组数据match方法match接受一个正则表达式作为参数。如果正则表达式中有g标示, 将返回与完整正则表达式匹配的所有结果,但不会返回捕获组。如果没有使用g标示,则仅返回第一个完整匹配及其相关的捕获组。var regex = /(\d{4})-(\d{2})-(\d{2})/gvar string = “2017-06-12 2017-06-12”// [“2017-06-12”, “2017-06-12”]// 返回与完整正则表达式匹配的所有结果, 不含分组的结果string.match(regex)var regex = /(\d{4})-(\d{2})-(\d{2})/var string = “2017-06-12 2017-06-12”// 只返回第一个完整匹配和其分组// [“2017-06-12”, “2017”, “06”, “12”, index: 0, input: “2017-06-12 2017-06-12”, groups: undefined]string.match(regex)exec方法exec方法接受一个字符串作为参数。如果exec匹配失败将会返回null, 如果匹配成功exec方法将会返回一个数组。返回的数组将完全匹配成功的文本作为第一项,而分组匹配的结果在数组位置0的后面。返回的结果同时拥有index属性, 标示了匹配字符为于原始字符的索引。input属性则是原始的字符串。注意当正则对象是否包含g返回结果是不一样的。如果正则中含有g标示, 那么正则对象的lastIndex(下一次匹配开始的位置), 会更新。而如果不含有g, 正则的lastIndex不会更新。var regex = /(\d{4})-(\d{2})-(\d{2})/var string = “2017-06-12 2017-06-12”// [“2017-06-12”, “2017”, “06”, “12”, index: 0, input: “2017-06-12 2017-06-12”, groups: undefined]// regex.lastIndex === 0regex.exec(string)// [“2017-06-12”, “2017”, “06”, “12”, index: 0, input: “2017-06-12 2017-06-12”, groups: undefined]// regex.lastIndex === 0regex.exec(string)var regex = /(\d{4})-(\d{2})-(\d{2})/gvar string = “2017-06-12 2017-06-12”// [“2017-06-12”, “2017”, “06”, “12”, index: 0, input: “2017-06-12 2017-06-12”, groups: undefined]regex.exec(string)// [“2017-06-12”, “2017”, “06”, “12”, index: 11, input: “2017-06-12 2017-06-12”, groups: undefined]// regex.lastIndex === 21regex.exec(string)RegEx我们也可以通过RegEx全局的构造函数来获取分组匹配的结果。构造函数的全局属性$1到$9存储了分组匹配的结果。var regex = /(\d{4})-(\d{2})-(\d{2})/gvar string = “2017-06-12 2017-06-12”// 任何正则操作即可regex.exec(string)// “2017"RegExp.$1替换分组数据我们可以通过replace方法配合分组匹配的结果, 实现替换分组数据replacestr.replace(regexp|substr, newSubStr|func)regexp 一个正则表达式对象,该正则所匹配的内容会被replace的第二个参数(或者函数的返回值)替换掉substr 当str中含有substr, 会被第二个参数替换, 仅有第一个匹配项会被替换newSubStr 用于替换掉第一个参数在原字符串中的匹配部分的字符串。该字符串中可以内插一些特殊的变量名(见下表)func 函数的返回值将替换掉第一个参数匹配到的结果变量名含义$1, $2, $3……第n个分组匹配的结果$插入当前匹配的子串左边的内容$'插入当前匹配的子串右边的内容$&amp;当前匹配的子串// "????loHel????"'????Hello????'.replace(/(Hel)(lo)/, '$2$1')// "????ello????ello????"// H被替换为ello????'????Hello????'.replace(/H/, "$'")// "????????ello????"// H被替换为????'????Hello????'.replace(/H/, "$")指定一个函数作为参数函数的返回值作为替换字符串。 (注意:上面提到的特殊替换参数在这里不能被使用。) 另外要注意的是,如果第一个参数是正则表达式,并且其为全局匹配模式,那么这个方法将被多次调用,每次匹配都会被调用。// 函数每匹配到一次, 就会被调用’????????????????????’.replace(’/????/g’, function () { return ‘????’})函数的参数含义match当前匹配的子串p1, p2, …… pn匹配的分组数据示例将'2019-01-01’替换为01/01/2019var str = ‘2019-01-01’var reg = /(\d{4})-(\d{2})-(\d{2})/// 01/01/2019var result = str.replace(reg, ‘$2/$3/$1’)// 01/01/2019result = str.replace(reg, function (match, year, month, day) { return ${month}/${day}/${year}})反向引用我们现在有一个需求, 使用一个正则表达式匹配如下格式的????日期字符串2019-01-01, 2019.01.01, 2019/01/01, 并且前后的分割符号需要保持一致var reg = /\d{4}(/|.|-)\d{2}(/|.|-)\d{2}/???? 上面的正则达到了最基本的目的, 但是我们还没有解决前后分割符需要保持一致的问题。这时我们可以到反向引用, 1表示第一个分组所匹配到的具体的字符, 2, 3同理var reg = /\d{4}(-|/|.)\d{2}\1\d{2}/括号嵌套var regex = /^((\d)(\d(\d)))\1\2\3\4$/var string = “1231231233”// 分组一// \d\d\d \1对应 123// 分组二// \d \2 对应 1// 分组三// \d\d \3 对应 23// 分组四// \d \4 对应31010表示第10个分组呢?还是1和0?10表示的是第十个分组引用不存在的分组引用不存在的分组不会报错。例如2, 2分组不存在, 2匹配的就是字符串"2"如果分组后面添加量词分组后面有量词的话,分组最终捕获到的数据是最后一次的匹配var str = ‘12345’var reg = /\d+/var reg1 = /(\d)+/// [“12345”, index: 0, input: “12345”, groups: undefined]str.match(reg)// [“12345”, index: 0, input: “12345”, groups: undefined]str.match(reg1)// \1 应当是匹配的最后一次结果var regex = /(\d)+ \1/;// falseregex.test(“12345 1”)// trueregex.test(“12345 5”) );非捕获括号之前的括号都被称为捕获型的分组, 捕获到的组的数据会在API中引用。如果只想使用括号最原始的功能,不在API和反向引用中使用可以使用非捕获括号。var str = ‘HelloWorld’var reg1 = /(?:Hello)(?:World)/var reg2 = /(Hello)(World)/// [“HelloWorld”, index: 0, input: “HelloWorld”, groups: undefined]// 捕获组的数据不会引用reg1.exec(str)// [“HelloWorld”, “Hello”, “World”, index: 0, input: “HelloWorld”, groups: undefined]reg2.exec(str)示例实现trim功能第一种思路是匹配空格, 然后替换空格为空字符串var reg = /^\s+|\s+$/gvar str = ’ reg ‘str.replace(reg, ‘’)第二种思路是使用分组把内容提取出来, 进行替换。var str = ’ reg ‘var reg = /^\s+(.)\s+$/gstr.replace(reg, ‘$1’)如果使用量词, 我们需要使用惰性匹配, 因为(.)s$中(.)的部分会匹配除了最后一个空格之外的其他空格var str = ’ reg ‘var reg = /^\s(.)\s$/gstr.replace(reg, ‘$1’)将每个单词的首字母转换成大写var str = ‘hello world’// Hello World// 我们匹配单词边界后的第一个字母str.replace(/\b\w{1}/g, function (word) { return word.toLocaleUpperCase()})匹配成对标签我们可以使用反向引用, 我们将前面的标签作为分组用括号包起来, 1将会是分组匹配的结果。我们这样就能保证前后两个标签的类型是一致的var reg = /<([^>]+)>\w+</\1>/// truereg.test(’<p>123</p>’)// falsereg.test(’<p>123</div>’)