企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
**(1)概述** 正则表达式的括号表示分组匹配,括号中的模式可以用来匹配分组的内容。 ~~~ /fred+/.test('fredd') // true /(fred)+/.test('fredfred') // true ~~~ 上面代码中,第一个模式没有括号,结果`+`只表示重复字母`d`,第二个模式有括号,结果`+`就表示匹配`fred`这个词。 下面是另外一个分组捕获的例子。 ~~~ var m = 'abcabc'.match(/(.)b(.)/); m // ['abc', 'a', 'c'] ~~~ 上面代码中,正则表达式`/(.)b(.)/`一共使用两个括号,第一个括号捕获`a`,第二个括号捕获`c`。 注意,使用组匹配时,不宜同时使用`g`修饰符,否则`match`方法不会捕获分组的内容。 ~~~ var m = 'abcabc'.match(/(.)b(.)/g); m // ['abc', 'abc'] ~~~ 上面代码使用带`g`修饰符的正则表达式,结果`match`方法只捕获了匹配整个表达式的部分。这时必须使用正则表达式的`exec`方法,配合循环,才能读到每一轮匹配的组捕获。 ~~~ var str = 'abcabc'; var reg = /(.)b(.)/g; while (true) { var result = reg.exec(str); if (!result) break; console.log(result); } // ["abc", "a", "c"] // ["abc", "a", "c"] ~~~ 正则表达式内部,还可以用`\n`引用括号匹配的内容,`n`是从1开始的自然数,表示对应顺序的括号。 ~~~ /(.)b(.)\1b\2/.test("abcabc") // true ~~~ 上面的代码中,`\1`表示第一个括号匹配的内容(即`a`),`\2`表示第二个括号匹配的内容(即`c`)。 下面是另外一个例子。 ~~~ /y(..)(.)\2\1/.test('yabccab') // true ~~~ 括号还可以嵌套。 ~~~ /y((..)\2)\1/.test('yabababab') // true ~~~ 上面代码中,`\1`指向外层括号,`\2`指向内层括号。 组匹配非常有用,下面是一个匹配网页标签的例子。 ~~~ var tagName = /<([^>]+)>[^<]*<\/\1>/; tagName.exec("<b>bold</b>")[1] // 'b' ~~~ 上面代码中,圆括号匹配尖括号之中的标签,而`\1`就表示对应的闭合标签。 上面代码略加修改,就能捕获带有属性的标签。 ~~~ var html = '<b class="hello">Hello</b><i>world</i>'; var tag = /<(\w+)([^>]*)>(.*?)<\/\1>/g; var match = tag.exec(html); match[1] // "b" match[2] // " class="hello"" match[3] // "Hello" match = tag.exec(html); match[1] // "i" match[2] // "" match[3] // "world" ~~~ **(2)非捕获组** `(?:x)`称为非捕获组(Non-capturing group),表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。 非捕获组的作用请考虑这样一个场景,假定需要匹配`foo`或者`foofoo`,正则表达式就应该写成`/(foo){1, 2}/`,但是这样会占用一个组匹配。这时,就可以使用非捕获组,将正则表达式改为`/(?:foo){1, 2}/`,它的作用与前一个正则是一样的,但是不会单独输出括号内部的内容。 请看下面的例子。 ~~~ var m = 'abc'.match(/(?:.)b(.)/); m // ["abc", "c"] ~~~ 上面代码中的模式,一共使用了两个括号。其中第一个括号是非捕获组,所以最后返回的结果中没有第一个括号,只有第二个括号匹配的内容。 下面是用来分解网址的正则表达式。 ~~~ // 正常匹配 var url = /(http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec('http://google.com/'); // ["http://google.com/", "http", "google.com", "/"] // 非捕获组匹配 var url = /(?:http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec('http://google.com/'); // ["http://google.com/", "google.com", "/"] ~~~ 上面的代码中,前一个正则表达式是正常匹配,第一个括号返回网络协议;后一个正则表达式是非捕获匹配,返回结果中不包括网络协议。 **(3)先行断言** `x(?=y)`称为先行断言(Positive look-ahead),`x`只有在`y`前面才匹配,`y`不会被计入返回结果。比如,要匹配后面跟着百分号的数字,可以写成`/\d+(?=%)/`。 “先行断言”中,括号里的部分是不会返回的。 ~~~ var m = 'abc'.match(/b(?=c)/); m // ["b"] ~~~ 上面的代码使用了先行断言,`b`在`c`前面所以被匹配,但是括号对应的`c`不会被返回。 **(4)先行否定断言** `x(?!y)`称为先行否定断言(Negative look-ahead),`x`只有不在`y`前面才匹配,`y`不会被计入返回结果。比如,要匹配后面跟的不是百分号的数字,就要写成`/\d+(?!%)/`。 ~~~ /\d+(?!\.)/.exec('3.14') // ["14"] ~~~ 上面代码中,正则表达式指定,只有不在小数点前面的数字才会被匹配,因此返回的结果就是`14`。 “先行否定断言”中,括号里的部分是不会返回的。 ~~~ var m = 'abd'.match(/b(?!c)/); m // ['b'] ~~~ 上面的代码使用了先行否定断言,`b`不在`c`前面所以被匹配,而且括号对应的`d`不会被返回。