RegExphtml
Regular Expression,正则表达式是一种表达 文本模式(字符串结构) 的式子。web
经常用来按照“给定模式”匹配文本。好比,正则表达式给出一个 Email 地址的模式,而后用它来肯定一个字符串是否为 Email 地址。正则表达式
JavaScript 的正则表达式体系是参照 Perl 5 创建的数组
var regex = /xyz/;
var regex = /xyz/ig; // i 和 g 为两个修饰符
var regex = new RegExp('xyz');
var regex = new RegExp('xyz', 'i'); // i 和 g 为两个修饰符
RegExp.prototype.lastIndex
返回一个整数,表示下一次开始搜索的位置。该属性可读写,可是只在进行连续搜索时有意义RegExp.prototype.source
返回正则表达式的字符串形式(不包括反斜杠),该属性只读
/a/
匹配a
,/b/
匹配b
),那么它们就叫作“字面量字符”(literal characters)。.
)匹配除回车(\r
)、换行(\n
) 、行分隔符(\u2028
)和段分隔符(\u2029
)之外的全部字符0xFFFF
字符,点字符不能正确匹配,会认为这是两个字符^ 表示字符串的开始位置网络
$ 表示字符串的结束位置app
|
)
/11|22/.test('911'); // true 指定必须匹配到 或 1122
/ab|cd/
指的是匹配ab
或者cd
,而不是指匹配b
或者c
/a( |\t)b/.test('a\tb'); // true
\
、\*
、+
、?
、()
、[]
、{}
等等,将在下文解释
+
,就要写成\+
^
.
[
$
(
)
|
*
+
?
{
\
RegExp
方法生成正则对象,转义须要使用两个斜杠,由于字符串内部会先转义一次
(new RegExp('1\+1')).test('1+1'); // false (new RegExp('1\\+1')).test('1+1'); // true
// 做为构造函数,参数是一个字符串。可是,在字符串内部,反斜杠也是转义字符,因此它会先被反斜杠转义一次,而后再被正则表达式转义一次,所以须要两个反斜杠转义
对一些不能打印的特殊字符,提供了表达方法函数
\cX 用来匹配控制字符,表示Ctrl-[X],其中的X是A-Z之中任一个英文字母,
ui
[\b] 匹配退格键(U+0008),不要与\b混淆google
\n 匹配换行键编码
\r 匹配回车键
\t 匹配制表符 tab(U+0009)
\v 匹配垂直制表符(U+000B)
\f 匹配换页符(U+000C)
\0 匹配null字符(U+0000)
\xhh 匹配一个以两位十六进制数(\x00-\xFF)表示的字符
\uhhhh 匹配一个以四位十六进制数(\u0000-\uFFFF)表示的 Unicode 字符
[ ] 表示有一系列字符可供选择,只要匹配其中一个就能够了
全部可供选择的字符都放在方括号内,
好比[xyz]
表示x
、y
、z
之中任选一个匹配
[^]
,则表示除了字符类之中的字符,其余字符均可以匹配[^xyz]
表示除了x
、y
、z
以外均可以匹配[^]
,就表示匹配一切字符,其中包括换行符
.
)是不包括换行符的
var s = 'Please yes\nmake my day!'; s.match(/yes.*day/); // null 含有一个换行符,点号不包括换行符,因此第一个正则表达式匹配失败 s.match(/yes[^]*day/); // [ 'yes\nmake my day'] 包含一切字符,因此匹配成功s[^]
[abc]
能够写成[a-c]
,[0123456789]
能够写成[0-9]
,同理[A-Z]
表示26个大写字母[A-z]
,表面上它是选中从大写的A
到小写的z
之间52个字母,可是因为在 ASCII 编码之中,大写字母与小写字母之间还有其余字符,结果就会出现意料以外的结果var str = "\u0130\u0131\u0132"; /[\u0128-\uFFFF]/.test(str); // true // \u0128-\uFFFF 表示匹配码点在0128到FFFF之间的全部字符
指的是某些常见模式的简写方式
\d 匹配0-9之间的任一数字,至关于 [0-9]
\D 匹配全部0-9之外的字符,至关于 [^0-9]
\w 匹配任意的字母、数字和下划线,至关于 [A-Za-z0-9_]
\W 除全部字母、数字和下划线之外的字符,至关于 [^A-Za-z0-9_]
\s 匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]
var html = "<b>Hello</b>\n<i>world!</i>"; /[\S\s]*/.exec(html)[0]; // "<b>Hello</b>\n<i>world!</i>" // [\S\s]指代一切字符
\S 匹配非空格的字符,至关于[^ \t\r\n\v\f]
\b 匹配词的边界
\B 匹配非词边界,即在词的内部
// \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
模式的精确匹配次数,使用大括号 { } 表示重复类
{n}
表示刚好重复n
次,
{n,}
表示至少重复n
次,
{n,m}
表示重复很多于n
次,很少于m
次
/lo{2}k/.test('look'); // true 指定o连续出现2次 /lo{2,5}k/.test('looook'); // true 指定o连续出现2次到5次之间
用来设定某个模式出现的次数
? 问号表示某个模式出现0次或1次,等同于{0, 1}
* 星号表示某个模式出现0次或屡次,等同于{0,}
+ 加号表示某个模式出现1次或屡次,等同于{1,}
// t 出现0次或1次 /t?est/.test('test'); // true /t?est/.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"] // 模式是/a+/,表示匹配1个a或多个a,那么到底会匹配几个a呢? // 由于默认是贪婪模式,会一直匹配到字符a不出现为止,因此匹配结果是3个a
var s = 'aaa'; s.match(/a+?/) // ["a"] 模式结尾添加了一个问号/a+?/,这时就改成非贪婪模式,一旦条件知足,就再也不往下匹配
表示模式的附加规则,放在正则模式的最尾部
能够单个使用,也能够多个一块儿使用
// 正则模式含有g修饰符,每次都是从上一次匹配成功处,开始向后匹配。 var regex = /b/g; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // false // 由于字符串abba只有两个b,因此前两次匹配结果为true,第三次匹配结果为false
i
修饰符之后表示忽略大小写(ignorecase)
/abc/.test('ABC'); // false /abc/i.test('ABC'); // true // 加了i修饰符之后,不考虑大小写,因此模式abc匹配字符串ABC
^
和 $
的行为m
修饰符之后,^
和 $
还会匹配行首和行尾,即 ^
和 $
会识别换行符(\n
)
/world$/.test('hello world\n'); // false /world$/m.test('hello world\n'); // true // 字符串结尾处有一个换行符。若是不加m修饰符,匹配不成功,由于字符串的结尾不是world;加上之后,$能够匹配行尾
/^b/m.test('a\nb'); // true
// 若是不加m
修饰符,就至关于b
只能处在字符串的开始处。加上b
修饰符之后,换行符\n
也会被认为是一行的开始mbb\n
括号表示分组匹配,括号中的模式能够用来匹配分组的内容
/fred+/.test('fredd'); // true 结果+只表示重复字母d /(fred)+/.test('fredfred'); // true 有括号,结果+就表示匹配fred这个词
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"]
/(.)b(.)\1b\2/.test("abcabc"); // 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"
表示不返回该组匹配的内容,即这个括号中匹配的内容不计入结果
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", "/"]
x
只有在 y前面才匹配,y 不会被计入返回结果。即括号里的部分是不会返回的
好比,要匹配后面跟着百分号的数字,能够写成/\d+(?=%)/
。
var m = 'abc'.match(/b(?=c)/); m // ["b"] 使用了先行断言,b在c前面因此被匹配,可是括号对应的c不会被返回
只有不在y
前面才匹配,y
不会被计入返回结果。即括号里的部分是不会返回的
好比,要匹配后面跟的不是百分号的数字,就要写成/\d+(?!%)/
/\d+(?!\.)/.exec('3.14') // ["14"]
b
不在c
前面因此被匹配,并且括号对应的d
不会被返回
var m = 'abd'.match(/b(?!c)/); m // ['b']
/cat/.test('cats and dogs'); // true 验证参数字符串之中是否包含 cat
g
修饰符时,能够经过正则对象的 lastIndex
属性指定开始搜索的位置var r = /x/g; var s = '_x_x'; r.lastIndex // 0 r.test(s) // true r.lastIndex // 2 r.test(s) // true r.lastIndex // 4 r.test(s) // false
lastIndex
属性只对同一个正则表达式有效,因此下面这样写是错误的
var count = 0; while (/a/g.test('babaa')){ count++; } // 无限循环,由于while循环的每次匹配条件都是一个新的正则表达式,致使lastIndex属性老是等于0
null
var s = '_x_x'; var r1 = /x/; var r2 = /y/; r1.exec(s); // ["x"] r2.exec(s); // null
length
属性等于组匹配的数量再加1var s = '_x_x'; var r = /_(x)/; r.exec(s); // ["_x", "x"] 返回一个数组。第一个成员是整个匹配的结果,第二个成员是圆括号匹配的结果。
exec
方法的返回数组还包含如下两个属性:
var r = /a(b+)a/; var arr = r.exec('_abbba_aba_'); arr // ["abbba", "bbb"] arr.index // 1 属性等于1,是由于从原字符串的第二个位置开始匹配成功 arr.input // "_abbba_aba_"index
g
修饰符,则可使用屡次exec
方法,下一次搜索的位置从上一次匹配成功结束的位置开始
var reg = /a/g; var str = 'abc_abc_abc' var r1 = reg.exec(str); r1 // ["a"] r1.index // 0 reg.lastIndex // 1 var r2 = reg.exec(str); r2 // ["a"] r2.index // 4 reg.lastIndex // 5 var r3 = reg.exec(str); r3 // ["a"] r3.index // 8 reg.lastIndex // 9 var r4 = reg.exec(str); r4 // null reg.lastIndex // 0
// 前三次都是从上一次匹配结束的位置向后匹配。
// 当第三次匹配结束之后,整个字符串已经到达尾部,匹配结果返回,正则实例对象的属性也重置为,意味着第四次匹配将从头开始nulllastIndex0
利用g
修饰符容许屡次匹配的特色,能够用一个循环完成所有匹配
var reg = /a/g; var str = 'abc_abc_abc' while(true) { var match = reg.exec(str); // 匹配到末尾,匹配失败,返回 null if (!match) break; console.log('#' + match.index + ':' + match[0]); } // #0:a // #4:a // #8:a
在字符串中有 4 中与正则表达式相关的实例方法。
exec
方法很是相似:匹配成功返回一个数组,匹配失败返回 null
g
修饰符,会一次性返回全部匹配成功的结果lastIndex
属性,对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"] 一次返回只有一个结果的一个数组 lastIndex 后移
-1
'_x_x'.search(/x/); // 1 第一个匹配结果出如今字符串的1号位置
str.replace(search, replacement);
'aaa'.replace('a', 'b'); // "baa" 'aaa'.replace(/a/, 'b'); // "baa" 'aaa'.replace(/a/g, 'b'); // "bbb" 使用了修饰符,致使全部的都被替换掉了gb
g
修饰符,就替换第一个匹配成功的值,不然替换全部匹配成功的值var str = ' #id div.class '; str.replace(/^\s+|\s+$/g, ''); // "#id div.class"
replace
方法的第二个参数可使用美圆符号$
,用来指代所替换的内容
$& 匹配的子字符串。 $` 匹配结果前面的文本。 $' 匹配结果后面的文本。 $n 匹配成功的第n组内容,n是从1开始的天然数。 $$ 指代美圆符号$。
'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.
replace
方法第二个参数的替换函数,能够接受多个参数。
var prices = { 'p1': '$1.99', 'p2': '$9.99', 'p3': '$5.00' }; var template = '<span id="p1"></span>' + '<span id="p2"></span>' + '<span id="p3"></span>'; template.replace( /(<span id=")(.*?)(">)(<\/span>)/g, function(match, $1, $2, $3, $4){ // 有四个括号,因此会产生四个组匹配,在匹配函数中用到表示。匹配函数的做用是将价格插入模板中 return $1 + $2 + $3 + prices[$2] + $4; } ); // "<span id="p1">$1.99</span><span id="p2">$9.99</span><span id="p3">$5.00</span>"$1$4
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*/); // [ '', '*', '*' ] // 分割规则是0次或屡次的a,因为正则默认是贪婪匹配,因此例一的第一个分隔符是aaa,第二个分割符是a,将字符串分红三个部分,包含开始处的空字符串 // 例二 'aaa**a*'.split(/a*/); // ["", "*", "*", "*"] // 第一个分隔符是aaa,第二个分隔符是0个a(即空字符),第三个分隔符是a,因此将字符串分红四个部分
'aaa*a*'.split(/(a*)/); // [ '', 'aaa', '*', 'a', '*' ] // 正则表达式使用了括号,第一个组匹配是aaa,第二个组匹配是a,它们都做为数组成员返回
好比,[abc]
能够写成[a-c]
,[0123456789]
能够写成[0-9]
,同理[A-Z]
表示26个大写字母