有关正则表达式的知识可以参考:
正则表达式必知必会(一)
正则表达式必知必会(二)
正则表达式必知必会(三)
创建正则表达式
字面量
ECMAScript通过RegExp类型来支持正则表达式。
使用下面的语法就可以创建一个正则表达式:
var expression = /pattern/flags;
- pattern:模式部分,可以是任何简单或者复杂的正则表达式,可以包含字符类、限定符、分组、向前查找以及回溯引用。
- flags:每个表达式可以带有一或多个标志,用以表明正则表达式的行为。
正则表达式的匹配模式支持下列三个标识:
- g:全局模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时就立即停止。
- i:表示不区分大小写,即在确定匹配项时忽略模式与字符串的大小写。
- m:表示多行模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。
因此,一个正则表达式就是一个模式与上述三个标志的组合体。
下面有几个正则表达式的例子:
//匹配所有at
var pattern1 = /at/g;
//匹配第一个bat或cat,不区分大小写
var pattern2 = /[bc]at/i
//匹配所有以at结尾的三个字符的组合,不区分大小写
var pattern3 = /.at/gi
与其他语言中的正则表达式类似,模式中使用的所有元字符都必须转义。
正则表达式中的元字符包括:
( [ { \ ^ $ | ) ? * + . ] }
如果要匹配元字符本身的话,必须进行转义,下面是几个使用元字符与使用其转义的例子:
//匹配第一个bat或cat,不区分大小写
var pattern2 = /[bc]at/i
//匹配第一个[bc]at,不区分大小写
var pattern1 = /\[bc\]at/i;
//匹配所有以at结尾的三个字符的组合,不区分大小写
var pattern3 = /.at/gi
//匹配所有.at,不区分大小写
var pattern2 = /\.at/gi
构造函数
前面举的这些例子都是以字面量形式来定义的正则表达式。另一种创建正则表达式的方式是使用RegExp构造函数,它接收两个参数:
- 要匹配的字符串模式
- 可选的标志字符串
可以使用字面量定义的任何表达式,都可以使用构造函数来定义。
//匹配第一个bat或cat,不区分大小写
var pattern1 = /[bc]at/i;
var pattern2 = new RegExp("[bc]at","i");
pattern1和pattern2是两个完全等价的正则表达式。
要注意的是,传递给RegExp构造函数的两个参数都是字符串(不能把正则表达式字面量传递给RegExp构造函数)。
由于RegExp构造函数的模式参数是字符串,而”\”在js字符串中表示转义符,如果在字符串中像在正则表达式字面量里那样直接使用\来转义,那么只能说明在js字符串中转义,而没有达到在正则表达式里转义的含义,因此在某些情况下要对字符进行双重转义。下面右边给出了一些使用RegExp构造函数时使用的字符串:
/\[bc\]at/
:"\\[bc\\]at"
/\.at/
:"\\.at"
/name\/age/
:"name\\/age"
/\d.\d{1,2}/
:"\\d.\\d{1,2}"
/\w\\hello\\123/
:"\\w\\\\hello\\\\123"
稍微解释一下,前4个字符串都是将用于转义其他字符的\
转义成\\
。而最后一个正则表达式字符串中,我们想匹配\本身,因此本来是\\
,但是由于在js字符串中,所以再进行一次转义,变为\\\\
。
使用正则表达式字面量和使用RegExp构造函数创建的每一个新RegExp实例都是一个新实例。
RegExp实例属性
RegExp的每个实例都具有下列属性,通过这些属性可以取得有关模式的各种信息:
- global:布尔值,表示是否设置了g标志
- ignoreCase:布尔值,表示是否设置了i标志
- multiline:布尔值,表示是否设置了m标志
- lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0算起
- source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
通过这些属性可以获知一个正则表达式的各方面信息,但其实没有多大用处,因为这些信息全部包含在模式声明中。
RegExp实例方法
exec()
此方法专门为捕获组设计的。捕获组就是正则表达式中子表达式匹配的内容。
接收一个参数,即要应用模式的字符串。
返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。
返回的数组虽然是Array的实例,但是包含两个额外的属性:
- index:匹配项在字符串中的位置
- input:应用正则表达式的字符串
在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果没有捕获组则该数组只有一项)。
var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi
var matches = pattern.exec(text);
matches.index; //0
matches.input; //"mom and dad and baby"
matches[0]; //"mom and dad and baby"
matches[1]; //"and dad and baby"
matches[2]; //"and baby"
这个例子中包含两个捕获组。最内部的捕获组匹配“and baby”,而包含他的捕获组匹配“and dad”或“and dad and baby”。
当把字符串传入方法中后,发现了一个匹配项,因为整个字符串本身与模式匹配,因此matches数组的index属性为0。
数组中的第一项是匹配的整个字符串,第二项包含于第一个捕获组匹配的内容,第三项包含与第二个捕获组匹配的内容。
对于exec()方法而言,即使在模式中设置了全局标志g,它每次也只会返回一个匹配项,但是每次调用exec()方法是时都会在字符串中继续查找字符串。在不设置全局标志的情况下,在同一个字符串上多次调用exec()方法,始终会返回第一个匹配项的信息。
var text = "cat, bat, sat, fat";
var pattern1 = /.at/;
//第一次在text上调用方法
var matches = pattern1.exec(text);
matches.index; //0
matches[0]; //cat
pattern1.lastIndex; //0 表示下次匹配的位置,可以看出还是从头开始匹配
//第二次在text上调用方法
matches = pattern1.exec(text);
matches.index; //0
matches[0]; //cat
pattern1.lastIndex; //0 表示下次匹配的位置,可以看出还是从头开始匹配
//使用全局标志g
var pattern2 = /.at/g;
//第一次在text上调用方法
var matches = pattern2.exec(text);
matches.index; //0
matches[0]; //cat
pattern2.lastIndex; //3 表示下次匹配的位置,可以看出是从当前查找位置继续向下匹配
//第二次在text上调用方法
var matches = pattern2.exec(text);
matches.index; //5
matches[0]; //bat
pattern1.lastIndex; //8 表示下次匹配的位置,可以看出是从当前查找位置继续向下匹配
这个例子中的第一个模式pattern1不是全局模式,因此每次调用exec()返回的都是第一个匹配项“cat”。
而第二个模式pattern2是全局模式,因此每次调用exec()都会返回字符串中的下一个匹配项,直至搜索到字符串末尾位置。
另外,还需注意模式的lastIndex属性的变化情况,在全局模式下每次调用exec()方法后都会增加,而非全局模式下则一直不变。
test()
接收一个字符串参数。
在模式与该参数匹配的情况下返回true,否则返回false。
在只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容的情况下,使用这个方法非常方便。因此。test方法经常被应用在if语句中:
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/
if(pattern.test(text)){
alert("the pattern was matched")
}
这种用法经常被用在验证用户输入的场景下,因为我们只想知道输入是不是有效。
最后,RegExp实例继承的toLocaleString()和toString()方法都会返回正则表达式的字面量,与创建正则表达式的方式无关。
var pattern = new RegExp("\\[bc\\]at","gi");
pattern.toString(); // /\[bc\]at/gi
pattern.toLocaleString(); // /\[bc\]at/gi
正则表达式的valueOf()方法返回正则表达式本身。
RegExp构造函数属性
RegExp构造函数包含一些属性,这些属性适用于作用域中的所有正则表达式,并且基于所执行的最近一次正则表达式操作而变化。
这些属性有两种方式可以访问它们,它们分别有一个长属性名和一个短属性名。下面列出了构造函数的属性(括号内为短属性名):
- input($_):最近一次要匹配的字符串
- lastMatch($&):最近一次的匹配项
- lastParen($+):最近一次匹配的捕获组
- leftContext($`):input字符串中lastMatch之前的文本
- multiline($*):布尔值,表示是否所有表达式都是用多行模式
- rightContext($’):input字符串中lastMatch之后的文本
使用这些属性可以从exec()或test()执行的操作中提取出更具体的信息。
var text = "this has been a short summer";
var pattern = /(.)hort/g;\
if(pattern.test(text)){
RegExp.input; //"this has been a short summer"
RegExp.lastMatch; //"short"
RegExp.lastParen; //"s"
RegExp.leftContext;//"this has been a "
RegExp.multiline; //false
RegExp.rightContext;//" summer"
}
模式的局限性
尽管ECMAScript中的正则表达式功能还是比较完备的,但是仍缺少对一些高级正则表达式特性的支持:
- 向后查找
- 并集和交集
- 原子组
- Unicode支持
- 条件匹配
- 正则表达式注释