RegExp对象目录 概述正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,常常用作按照“给定模式”匹配文本的工具。比如,正则表达式给出一个 Email 地址的模式,然后用它来确定一个字符串是否为 Email 地址。JavaScript 的正则表达式体系是参照 Perl 5 建立的。 新建正则表达式有两种方法。一种是使用字面量,以斜杠表示开始和结束。 var regex = /xyz/; 另一种是使用 RegExp 构造函数。 var regex = new RegExp('xyz'); 上面两种写法是等价的,都新建了一个内容为 RegExp 构造函数还可以接受第二个参数,表示修饰符(详细解释见下文)。 var regex = new RegExp('xyz', 'i');// 等价于var regex = /xyz/i; 上面代码中,正则表达式 这两种写法——字面量和构造函数——在运行时有一个细微的区别。采用字面量的写法,正则对象在代码载入时(即编译时)生成;采用构造函数的方法,正则对象在代码运行时生成。考虑到书写的便利和直观,实际应用中,基本上都采用字面量的写法。 正则对象生成以后,有两种使用方式:
这两种使用方式下面都会介绍。 正则对象的属性和方法属性正则对象的属性分成两类。 一类是修饰符相关,返回一个布尔值,表示对应的修饰符是否设置。
var r = /abc/igm;r.ignoreCase // truer.global // truer.multiline // true 另一类是与修饰符无关的属性,主要是下面两个。
var r = /abc/igm;r.lastIndex // 0r.source // 'abc' test()正则对象的 /cat/.test('cats and dogs') // true 上面代码验证参数字符串之中是否包含 如果正则表达式带有 var r = /x/g;var s = '_x_x';r.lastIndex // 0r.test(s) // truer.lastIndex // 2r.test(s) // truer.lastIndex // 4r.test(s) // false 上面代码的正则对象使用了 带有 var r = /x/g;var s = '_x_x';r.lastIndex = 4;r.test(s) // false 上面代码指定从字符串的第五个位置开始搜索,这个位置是没有字符的,所以返回
var count = 0;while (/a/g.test('babaa')) count++; 上面代码会导致无限循环,因为 如果正则模式是一个空字符串,则匹配所有字符串。 new RegExp('').test('abc')// true exec()正则对象的 var s = '_x_x';var r1 = /x/;var r2 = /y/;r1.exec(s) // ['x']r2.exec(s) // null 上面代码中,正则对象 如果正则表示式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的 var s = '_x_x';var r = /_(x)/;r.exec(s) // ['_x', 'x'] 上面代码的
var r = /a(b+)a/;var arr = r.exec('_abbba_aba_');arr // ['abbba', 'bbb']arr.index // 1arr.input // '_abbba_aba_' 上面代码中的 如果正则表达式加上 var r = /a(b+)a/g;var a1 = r.exec('_abbba_aba_');a1 // ['abbba', 'bbb']a1.index // 1r.lastIndex // 6var a2 = r.exec('_abbba_aba_');a2 // ['aba', 'b']a2.index // 7r.lastIndex // 10var a3 = r.exec('_abbba_aba_');a3 // nulla3.index // TypeError: Cannot read property 'index' of nullr.lastIndex // 0var a4 = r.exec('_abbba_aba_');a4 // ['abbba', 'bbb']a4.index // 1r.lastIndex // 6 上面代码连续用了四次 利用 var r = /a(b+)a/g;var s = '_abbba_aba_';while(true) { var match = r.exec(s); if (!match) break; console.log(match[1]);}// bbb// b 正则对象的 var r = /a/;r.lastIndex = 7; // 无效var match = r.exec('xaxa');match.index // 1r.lastIndex // 7 上面代码设置了 如果有 var r = /a/g;r.lastIndex = 2;var match = r.exec('xaxa');match.index // 3r.lastIndex // 4 上面代码中, 如果正则对象是一个空字符串,则 var r1 = new RegExp('');var a1 = r1.exec('abc');a1 // ['']a1.index // 0r1.lastIndex // 0var r2 = new RegExp('()');var a2 = r2.exec('abc');a2 // ['', '']a2.index // 0r2.lastIndex // 0 字符串对象的方法字符串对象的方法之中,有4种与正则对象有关。
下面逐一介绍。 String.prototype.match()字符串对象的 var s = '_x_x';var r1 = /x/;var r2 = /y/;s.match(r1) // ['x']s.match(r2) // null 从上面代码可以看到,字符串的 如果正则表达式带有 var s = 'abba';var r = /a/g;s.match(r) // ['a', 'a']r.exec(s) // ['a'] 设置正则表达式的 var r = /a|b/g;r.lastIndex = 7;'xaxb'.match(r) // ['a', 'b']r.lastIndex // 0 上面代码表示,设置 String.prototype.search()字符串对象的 '_x_x'.search(/x/)// 1 上面代码中,第一个匹配结果出现在字符串的 该方法会忽略 var r = /x/g;r.lastIndex = 2; // 无效'_x_x'.search(r) // 1 上面代码中,正则表达式使用 String.prototype.replace()字符串对象的 str.replace(search, replacement) 搜索模式如果不加g修饰符,就替换第一个匹配成功的值,否则替换所有匹配成功的值。 'aaa'.replace('a', 'b') // 'baa''aaa'.replace(/a/, 'b') // 'baa''aaa'.replace(/a/g, 'b') // 'bbb' 上面代码中,最后一个正则表达式使用了
var str = ' #id div.class ';str.replace(/^\s+|\s+$/g, '')// '#id div.class' replace方法的第二个参数可以使用美元符号$,用来指代所替换的内容。
'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1')// 'world hello''abc'.replace('b', '[$`-$&-$\']')// 'a[a-b-c]c'
'3 and 5'.replace(/[0-9]+/g, function(match){ return 2 * match;})// '6 and 10'var a = 'The quick brown fox jumped over the lazy dog.';var pattern = /quick|brown|lazy/ig;a.replace(pattern, function replacer(match) { return match.toUpperCase();});// The QUICK BROWN fox jumped over the LAZY dog. 作为 var prices = { 'pr_1': '$1.99', 'pr_2': '$9.99', 'pr_3': '$5.00'};var template = '/* ... */'; // 这里可以放网页模块字符串template.replace( /()(<\/span>)/g, function(match, $1, $2, $3, $4){ return $1 + $2 + $3 + prices[$2] + $4; }); 上面代码的捕捉模式中,有四个括号,所以会产生四个组匹配,在匹配函数中用 String.prototype.split()字符串对象的 str.split(separator, [limit]) 该方法接受两个参数,第一个参数是分隔规则,第二个参数是返回数组的最大成员数。 // 非正则分隔'a, b,c, d'.split(',')// [ 'a', ' b', 'c', ' d' ]// 正则分隔,去除多余的空格'a, b,c, d'.split(/, */)// [ 'a', 'b', 'c', 'd' ]// 指定返回数组的最大成员'a, b,c, d'.split(/, */, 2)[ 'a', 'b' ] 上面代码使用正则表达式,去除了子字符串的逗号后面的空格。 // 例一'aaa*a*'.split(/a*/)// [ '', '*', '*' ]// 例二'aaa**a*'.split(/a*/)// ['', '*', '*', '*'] 上面代码的分割规则是0次或多次的 如果正则表达式带有括号,则括号匹配的部分也会作为数组成员返回。 'aaa*a*'.split(/(a*)/)// [ '', 'aaa', '*', 'a', '*' ] 上面代码的正则表达式使用了括号,第一个组匹配是“aaa”,第二个组匹配是“a”,它们都作为数组成员返回。 匹配规则正则表达式对字符串的匹配有很复杂的规则。下面一一介绍这些规则。 字面量字符和元字符大部分字符在正则表达式中,就是字面的含义,比如 /dog/.test('old dog') // true 上面代码中正则表达式的 除了字面量字符以外,还有一部分字符有特殊含义,不代表字面的意思。它们叫做“元字符”(metacharacters),主要有以下几个。 (1)点字符(.) 点字符( /c.t/ 上面代码中, (2)位置字符 位置字符用来提示字符所处的位置,主要有两个字符。
// test必须出现在开始位置/^test/.test('test123') // true// test必须出现在结束位置/test$/.test('new test') // true// 从开始位置到结束位置只有test/^test$/.test('test') // true/^test$/.test('test test') // false (3)选择符( 竖线符号( /11|22/.test('911') // true 上面代码中,正则表达式指定必须匹配 多个选择符可以联合使用。 // 匹配fred、barney、betty之中的一个/fred|barney|betty/ 选择符会包括它前后的多个字符,比如 /a( |\t)b/.test('a\tb') // true 上面代码指的是, 其他的元字符还包括 转义符正则表达式中那些有特殊含义的字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠。比如要匹配加号,就要写成 /1+1/.test('1+1')// false/1\+1/.test('1+1')// true 上面代码中,第一个正则表达式直接用加号匹配,结果加号解释成量词,导致不匹配。第二个正则表达式使用反斜杠对加号转义,就能匹配成功。 正则模式中,需要用斜杠转义的,一共有12个字符: (new RegExp('1\+1')).test('1+1')// false(new RegExp('1\\+1')).test('1+1')// true 上面代码中, 特殊字符正则表达式对一些不能打印的特殊字符,提供了表达方法。
字符类字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内,比如 /[abc]/.test('hello world') // false/[abc]/.test('apple') // true 上面代码表示,字符串“hello world”不包含 有两个字符在字符类中有特殊含义。 (1)脱字符(^) 如果方括号内的第一个字符是 /[^abc]/.test('hello world') // true/[^abc]/.test('bbc') // false 上面代码表示,字符串“hello world”不包含字母 如果方括号内没有其他字符,即只有 var s = 'Please yes\nmake my day!';s.match(/yes.*day/) // nulls.match(/yes[^]*day/) // [ 'yes\nmake my day'] 上面代码中,字符串
(2)连字符(-) 某些情况下,对于连续序列的字符,连字符( /a-z/.test('b') // false/[a-z]/.test('b') // true 上面代码中,当连字号(dash)不出现在方括号之中,就不具备简写的作用,只代表字面的含义,所以不匹配字符 以下都是合法的字符类简写形式。 [0-9.,][0-9a-fA-F][a-zA-Z0-9-][1-31] 上面代码中最后一个字符类 注意,字符类的连字符必须在头尾两个字符中间,才有特殊含义,否则就是字面含义。比如, 连字符还可以用来指定Unicode字符的范围。 var str = '\u0130\u0131\u0132';/[\u0128-\uFFFF]/.test(str)// true 另外,不要过分使用连字符,设定一个很大的范围,否则很可能选中意料之外的字符。最典型的例子就是 /[A-z]/.test('\\') // true 上面代码中,由于反斜杠( 预定义模式预定义模式指的是某些常见模式的简写方式。
下面是一些例子。 // \s的例子/\s\w*/.exec('hello world') // [' world']// \b的例子/\bworld/.test('hello world') // true/\bworld/.test('hello-world') // true/\bworld/.test('helloworld') // false// \B的例子/\Bworld/.test('hello-world') // false/\Bworld/.test('helloworld') // true 上面代码中, 通常,正则表达式遇到换行符( var html = 'Hello\nworld!';/.*/.exec(html)[0]// 'Hello' 上面代码中,字符串 var html = 'Hello\nworld!';/[\S\s]*/.exec(html)[0]// 'Hello\nworld!'// 另一种写法(用到了非捕获组)/(?:.|\s)*/.exec(html)[0]// 'Hello\nworld!' 上面代码中, 重复类模式的精确匹配次数,使用大括号( /lo{2}k/.test('look') // true/lo{2,5}k/.test('looook') // true 上面代码中,第一个模式指定 量词符量词符用来设定某个模式出现的次数。
// t出现0次或1次/test/.test('test') // true/test/.test('est') // true// t出现1次或多次/t+est/.test('test') // true/t+est/.test('ttest') // true/t+est/.test('est') // false// t出现0次或多次/t*est/.test('test') // true/t*est/.test('ttest') // true/t*est/.test('tttest') // true/t*est/.test('est') // true 贪婪模式上一小节的三个量词符,默认情况下都是最大可能匹配,即匹配直到下一个字符不满足匹配规则为止。这被称为贪婪模式。 var s = 'aaa';s.match(/a+/) // ['aaa'] 上面代码中,模式是 如果想将贪婪模式改为非贪婪模式,可以在量词符后面加一个问号。 var s = 'aaa';s.match(/a+/) // ['a'] 上面代码中,模式结尾添加了一个问号 除了非贪婪模式的加号,还有非贪婪模式的星号(
修饰符修饰符(modifier)表示模式的附加规则,放在正则模式的最尾部。 修饰符可以单个使用,也可以多个一起使用。 // 单个修饰符var regex = /test/i;// 多个修饰符var regex = /test/ig; (1)g修饰符 默认情况下,第一次匹配成功后,正则对象就停止向下匹配了。 var regex = /b/;var str = 'abba';regex.test(str); // trueregex.test(str); // trueregex.test(str); // true 上面代码中,正则模式不含 var regex = /b/g;var str = 'abba';regex.test(str); // trueregex.test(str); // trueregex.test(str); // false 上面代码中,正则模式含有 (2)i修饰符 默认情况下,正则对象区分字母的大小写,加上 /abc/.test('ABC') // false/abc/i.test('ABC') // true 上面代码表示,加了 (3)m修饰符
/world$/.test('hello world\n') // false/world$/m.test('hello world\n') // true 上面的代码中,字符串结尾处有一个换行符。如果不加 /^b/m.test('a\nb') // true 上面代码要求匹配行首的 组匹配(1)概述 正则表达式的括号表示分组匹配,括号中的模式可以用来匹配分组的内容。 /fred+/.test('fredd') // true/(fred)+/.test('fredfred') // true 上面代码中,第一个模式没有括号,结果 下面是另外一个分组捕获的例子。 var m = 'abcabc'.match(/(.)b(.)/);m// ['abc', 'a', 'c'] 上面代码中,正则表达式 注意,使用组匹配时,不宜同时使用 var m = 'abcabc'.match(/(.)b(.)/g);m// ['abc', 'abc'] 上面代码使用带 在正则表达式内部,可以用 /(.)b(.)\1b\2/.test('abcabc')// true 上面的代码中, 下面是另外一个例子。 /y(..)(.)\2\1/.test('yabccab') // true 括号还可以嵌套。 /y((..)\2)\1/.test('yabababab') // true 上面代码中, 组匹配非常有用,下面是一个匹配网页标签的例子。 var tagName = /<([^>]+)>[^<]*<\/\1>/;tagName.exec('bold')[1]// 'b' 上面代码中,圆括号匹配尖括号之中的标签,而 上面代码略加修改,就能捕获带有属性的标签。 var html = 'Helloworld';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)非捕获组
非捕获组的作用请考虑这样一个场景,假定需要匹配 请看下面的例子。 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)先行断言
“先行断言”中,括号里的部分是不会返回的。 var m = 'abc'.match(/b(?=c)/);m // ['b'] 上面的代码使用了先行断言, 再看一个例子。 /Jack (?=Sprat|Frost)/.test('Jack Frost') // true (4)先行否定断言
/\d+(?!\.)/.exec('3.14')// ['14'] 上面代码中,正则表达式指定,只有不在小数点前面的数字才会被匹配,因此返回的结果就是 “先行否定断言”中,括号里的部分是不会返回的。 var m = 'abd'.match(/b(?!c)/);m // ['b'] 上面的代码使用了先行否定断言, 参考链接
|
|
来自: 火骑士大大 > 《JavaScript》