正则表达式是描述字符模式的对象。RegExp类表达正则表达式,String和RegExp定义了方法,后者使用正则表达式进行强大的模式匹配和文本检索与替换功能。
正则表达式的定义
Js中正则表达式用RegExp对象表示,可以使用RegExp()构造函数来创建RegExp对象,不过更多的是通过一种特殊的直接量语法来创建。就像通过引号包裹字符的方式来定义字符串直接量一样。
Js中程序运行时每次遇到对象直接量诸如{}或[]的时候都会创建新对象,比如,如果在循环中写var a = [],则每次遍历都会创建一个新空数组。正则表达式直接量则与此不同,ECMAScript规范规定,一个正则表达式直接量在执行到它时转换为一个RegExp对象,同一段代码所表示的正则表达式直接量会在执行到它时转换为一个RegExp对象,同一段代码所表示正则表达式直接量的每次运算都返回同一个对象。
Ecmascript5规范则做了相反的规定,同一段代码所表示的正则表达直接是指每次运算都返回新对象。IE一直都是按照ecmascript5规范实现的。多数最新版本浏览器也开始遵循ecmascript5.
直接量字符
\o Null字符(\u0000)
\t 制表符(\u0009)
\n 换页符(\u000A)
\v 垂直制表符(\u000B)
\f 换页符(\u000C)
\r 回车符(\u000D)
\xnn由十六进制数据nn指定拉丁字符
\uxxxx由十六进制数XXXX 指定的Unicode字符
\cX控制字符^X,例如,\cJ等价于换行符\n
有特殊含义的标点符号:
^$ . * + ? = ! : | \ / () [] {}
有些符号只有在正则表达式的某些上下文中有特殊含义,在其它上下文中则被当成直接量处理。
如果想在表达式中使用这些字符的直接量,则必须用前缀\。
正则表达的字符类
[…] 方括号内的任意字符
[^…]不在方括号内的任意字符
. 除换行符和其它Unicode行终止符外的任意字符
\w 任何ASCII字符组成的单词,《=》[a-zA-Z0-9]
\W 任何不是ASCII字符组成的单词,《=》[^a-zA-Z0-9]
\s 任何Unicode空白字符
\S 任何非Unicode空白字符
\d 任何 ASCII数字,等价于[0-9]
\D 除了 ASCII数字之外的任何字符,等价于[^0-9]
\b在字符类中表示一个退格符 /[\b]/
重复
{n,m} 匹配前一项至少n次,但不能超过m次
{n,}匹配前一项n次或者更多次
{n} 匹配前一项n次
? 0次或1次
* 0次或多次
+ 1次或多次
使用”*”或”?”时注意,由于这些字符可能匹配0个字符,因此它们允许什么都不匹配,例如,/a*/ 实际与字符串”bbbb”匹配,因为它含有0个a
非贪婪的重复
在上表中的匹配重复字符是中能多地匹配,而且允许后续的正则表达式继续匹配。因此我们称之为“贪婪的”匹配。我们同样可以使用表达式进行非贪婪匹配,只须在待匹配的字符后跟随一个问号即可:?? +?*?或{1,5}?
如:/a+/可以匹配一个或多个连续的字母a。当使用”aaa”作为匹配字符串时,正则表达式会匹配它的三个字符。但是/a+?/也可以匹配一个或多连续字母a,但它是尽可能少地匹配。我们同样将”aaa”作为匹配字符串,但后一个模式只能匹配第一个a。使用非贪婪的匹配模式所得到的结果可能和期望并不一致。考虑以下正则表达式/a+b/,它匹配多个a和一个b,使用aaab作为匹配字符串时,它会匹配整个字符串。现在试一下非贪婪匹配版本 /a+?b/,当它匹配时,你期望它匹配一个a 和一个b。但实际上这个模式却匹配了整个字符串,和贪婪匹配一样。这是因为匹配总是会寻找字符串第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的,因此在这里不考虑它的子串中更短的匹配。
选择、分组和引用
正则表达式的语法还包括指定选择项、子表达式分组和引用前一子表达式的特殊字符。
“|”用于分隔供选择的字符。如/ab|cd|ef/可以匹配字符串”ab”,也可匹配“cd”还可以匹配“ef”。/d{3}|[a-z]{4}/匹配三位数字或四个小写字母。注意选择项的匹配是从左到右的。如果左边的选择项匹配,就忽略右边的匹配项,即使它产生更好的匹配。
圆括号:它有多种作用。
1.把单独的项组合成表达式,以便以像处理一个独立的单元那样用”|”,”*”,”+”或“?”等来对单元内的项进行处理。如:/java(script)?/可以匹配java 后面的”script”也可以没有。/(ab|cd)+|ef/可以匹配字符串”ef”也可匹配字符串”ab”或”cd”的一次或多次重复
2.完整的模式中定义子模式:当一个正则表达式成功地和目标字符串匹配时,可以从目标串中抽出和圆括号中的子模式相匹配的部分。如我们正在检索的模式是一个或多小写字母后跟随了一位或多位数字,则可以使用模式 /[a-z]+\d+/。但假定我们真正关心的是每个匹配尾部的数字,那如果将模式的数字部分放在括号中(/[a-z]+(\d+)/),就可以从检索到的匹配中抽取数字了。
3.允许在同一正则表达式的后部引用前面的子表达式:这是通过在字符“\”后加一位或多位数字来实现的。这个数字指定了带圆括号的子表达式的正则表达式中的位置。注意:因为子表达式可以嵌套另一个子表达式,所以它的位置是参与计数的左括号的位置。如([Ss]cript)可以用\2来指代
/([Jj]ava([Ss]cript)?)\sis\s(fun\w*)/
对正则表达式中前一个子表达式的引用,并不是指对子表达式模式的引用,而指的是与那个模式相匹配的文本的引用。这样,引用可以用于实施一条约束,即一个字符串各个单独部分包含的是完全相同的字符。例如,下面的正则表达式匹配就是位于单引号或双引号之内的0个或多个字符。但是,它并要求左侧和右侧的引号匹配。如/[‘”][^’”][‘”]/,如果要匹配左侧和右侧的引号,可以使用如下的引用
/([‘”])[^’”]*\1/这样就存在一条约束,那就是左侧的引号必须和右侧的引号相匹配。
注意不能在字符串类中使用引用下面这样是错的
/([‘”])[^\1]*\1/ 这个是错的
同样,在正则表达式不用创建带数字编码的引用,也可以对子表达式进行分组。它不是以“(”和“)”进行分组的,而是”(?”和”)”进行分组。看下面的这个模式
/([Jj]ava(?:[Ss]cript)?)\sis\s(fun\w*)/
(?:[Ss]cript)这个仅仅用于分组,因此复制符号”?”可以用到各个分组。这种改进的圆括号并生成引用,所以这个正则表达式中,\2引用了与(func\w*)匹配的文本
|选择,匹配的是该符号左边的子表达式或右边的表达式
(…) 组合,将几个项组合为一个单元,这个单元可通过*+?|等符号加以修饰,而且可以记住和这个组合匹配的字符串以供此后的引用使用
(?:) 只组合,把项组合到一个单元,但不记忆与该组相匹配的字符
\n和第n个分组第一次匹配字符相匹配,组是圆括号中的子表达式(也可以是嵌套的),组索引是从左到右的左括号数,注意(?:分组不编码
指定匹配位置
还有一些正则表达式的元素匹配的字符之间的位置,而不是实际字符。如\b匹配一个单词的边界,即位于\w 和\W之间的边界,或位于一个ascii单词与字符串的开始或结尾之间的边界。它不匹配某个可见的字符,它们指定匹配发生的合法位置。我们把这些元素称之为锚。
最常用的锚元素是:^它是匹配字符串的开始;
$用以匹配字符串的结束;
在符号 “(?=”和“)”之间加入一个表达式,它就是一个先行断言,用以说明圆括号内的表达式必须正确匹配,但并不是真正意义上的匹配,如/[Jj]ava([Ss]cript)?(?=\:)/这个正则表达式可以匹配”JavaScript : XXXXX”中的JavaScript,但不能匹配 “java in a Nutshell”中的java。就是因为它后面没有冒号!!!
带有”(?!”这个断言是负向先行断言,用以指定接下来的字符都不必匹配。如/Java(?!Script)([A-Z]\w*)/可以匹配”JavaBeans”,但不能匹配”Javanese”;它可以匹配”javaScript”但不能匹配“javaScripter” (这块有点绕。注意去掉Script后面跟的是首字母大写的任意字符串!!!!)
锚字符串
^ 匹配字符串的开头,在多行检索中,匹配一行的开头
$ 匹配字符串的结尾,在多行检索中,匹配一行的结尾
\b 匹配一个单词的边界,简言之,就是位于字符
\w和\W之间的位置,或位于字符\w和字符串的开头或结尾之间的位置。注意[\b]匹配的是退格
\B 匹配非单词边界的位置
(?=p)零宽正向先行断言,要求接下来的字符都与p匹配,但不包括p的那些字符
(?!p) 零宽负向先行断言,要求接下来的字符不与p匹配
修饰符
用以说明高级匹配模式的规则。和之前讨论的正则表达式语法不同,它放在/符号之外的,也就是说,它们不是出现在两条斜线之间,而第二条斜线之后,js只支持三个修饰符,
i用以说明模式匹配是不区分大小写。
g说明模式匹配应该是全局的,即应该找出被检索字符串的所有匹配。
m用以在多行模式中执行匹配,如果待检索的字符串包含多行那么^和$除了匹配整个字符串的开始和结尾之外,还能匹配每行的开始和结尾。