正则表达式是一个描述字符模式的对象。

Javascript的RegExp类表示正则表达式,String和RegExp都定义了方法,后者使用正则表达式进行强大的模式匹配和文本检索与替换功能。

定义

可以使用RegExp()构造函数来创建RegExp对象,不过RegExp对象更多的是通过一种特殊的直接量语法来创建。

正则表达式直接量定义为包含在一对斜杠(/)之间的字符,如:

1
var pattern = /s$/;

若使用构造函数:

1
var pattern = new RegExp("s$");

正则表达式的模式规则是由一个字符序列组成的。包括所有字母和数字在内,大多数的字符都是按照直接量仅描述待匹配的字符的。/java/可以匹配任何带有”java“子串的字符串。除此之外,正则表达式中还可以含有其它具有具体特殊语义的字符。

直接量字符

正则表达式中所有字母和数字都是按照字面含义进行匹配的。非字母的字符匹配需要通过\作为前缀进行转义。如下:

  • 字符 匹配
  • 字母和数字字符 自身
  • \o NUL字符\u0000
  • \t 制表符\u0009
  • \n 换行符\u000A
  • \v 垂直制表符\u000B
  • \f 换页符\u000C
  • \r 回车符\u000D
  • \xnn 由十六进制数nn指定的拉丁字符,例如\x0A等价于\n
  • \uxxxx 由十六进制数xxxx指定的Unicode字符,例如\u0009等价于\t
  • \cX 控制字符^X,例如,\cJ等价于换行符\n

此外还有一些标点符号有特殊含义:

^$.*+?=!:|\/()[]{}

若想匹配这些字符的直接量也要使用前缀\,其他标点符号如@、引号则没有特殊含义。

如果不记得哪些标点符号需要反斜线转义,可以在每个标点符号之前都加上反斜线。

字符类

将直接量字符单独放进方括号内就组成了字符类。一个字符类可以匹配它所包含的任意字符。/[abc]/可以匹配”a”、”b”、”c”中任意一个。^符号可以否定字符类。/[^abc]/匹配非”a”、”b”、”c”的任意字符。字符类使用连字符来表示字符范围。

  • 字符 匹配
  • [] 方括号内任意字符
  • [^] 不在方括号内的任意字符
  • . 除换行符和其他Unicode行终止符之外的任意字符
  • \w 任何ASC2字符组成的单词,等价于[a-zA-Z0-9]
  • \W 任何不是ASC2字符组成的单词,等价于[^a-zA-Z0-9]
  • \s 任何Unicode空白符
  • \S 任何非Unicode空白符的字符
  • \d 任何ASC2数字,等同于[0-9]
  • \D 除了ASC2数字外的其他字符,等同于[^0-9]
  • [\b] 退格直接量
重复
  • 字符 含义
  • {n,m} 匹配前一项至少n次但不能超过m次
  • {n,} 匹配前一项至少n次
  • {n} 匹配前一项n次
  • ? 匹配前一项0或1次,等价于{0,1}
  • + 匹配前一项1或多次,等价于{1,}
  • * 匹配前一项0多多次,等价于{0,}

例:

  • /\d{2,4}/ 匹配2~4个数字
  • /\w{3}\d?/ 匹配3个单词后加1个可选数字
  • /\s+java\s+/ 匹配前后可带有1或多个空格的字符串”java”
  • /[^(]*/ 匹配一个或多个非左括号的字符

上表列出的匹配重复字符为贪婪匹配,为尽可能多的匹配;非贪婪匹配只需要在待匹配的字符后跟随一个问号即可。”??”,”+?”,”*?”,”{1,5}?”。

例:

/a+/及/a+?/都可以匹配1个或多个连续的字母a,当字符串为”aaa”时,/a+/会匹配3个字符,/a+?/会匹配1个字符。

选择、分组、引用

| 用于分隔供选择的字符

/ab|cd|ef/ 可以匹配”ab”、”cd”、”ef”。

注意:选择项的匹配顺序是从左到右,直到发现了匹配项。如果左边的符合匹配,就忽略右边的匹配项。

/a|ab/匹配”ab”时,只匹配第一个字符。

()圆括号的作用:

  1. 把单独项组合成子表达式

    /java(script)?/ 加上圆括号可以对”script”应用?操作

  2. 定义子模式

  3. 允许同一正则表达式的后部引用前面的子表达式。这是通过在字符”\”后加一位或多为数字来实现的。

例如:

/[‘“][^’”]*[‘“]/ 匹配位于单引号或双引号之内的0个或多个字符,但并不要求两个引号匹配。

/([‘“])[^’”]*\1/ 匹配位于单引号或双引号之内的0个或多个字符,同时要求两个引号匹配。

如果使用(?:)那么意味着仅仅用于分组,引用并不带有数字编号。

指定匹配位置:

正则表达式中的锚字符:

  • ^ 匹配字符串的开头,在多行检索中,匹配一行的开头
  • $ 匹配字符串的结尾,在多行检索中,匹配一行的结尾
  • \b 匹配一个单词的边界,简言之,就是位于字符\w和\W之间的位置,或位于字符\w和字符串的开头或者结尾之间的位置
  • \B 匹配非单词边界的位置
  • (?=p) 零宽正向先行断言,要求接下来的字符都与p匹配,但不能包括匹配p的那些字符
  • (?!p) 零宽负向先行断言,要求接下来的字符不与p匹配

例如:

/[Jj]ava([Ss]cript)?(?=\:))/ 可以匹配”JavaScript:”,不能匹配”Java”;

/Java(?! Script)([A-Z]\w*)/ 可以匹配”Java”猴跟随一个大写字母和任意多个ASC2单词,但Java后面不能跟随Script。

修饰符

修饰符放在第二条/之后。

  • i 执行不区分大小写的匹配
  • g 执行一个全局匹配,简言之,即找到所有的匹配,而不是在找到第一个之后就停止。
  • m 多行匹配模式,^匹配一行的开头和字符串的开头,$匹配行的结束和字符串的结束。
用于模式匹配的String()方法
  • search(),参数为一个正则表达式,返回第一个与之匹配的子串的起始位置,如果找不到匹配的子串,它将返回-1.

    1
    "JavaScript".search(/script/i) //返回4

search()方法不支持全局检索,忽略修饰符g。

  • replace()方法用以执行检索和替换操作。第一个参数是正则表达式,第二个参数是要进行替换的字符串。

    1
    2
    //将所有不区分大小写的javascript都替换成大小写正确的Javascript
    text.replace(/javascript/gi, "JavaScript");
  • match()方法是最常用的String正则表达式方法。它的唯一参数就是一个正则表达式(或通过RegExp()构造函数将其转换为正则表达式),返回的是一个由匹配结果组成的数组。如果该正则表达式设置了修饰符g,则该方法返回的数组包含字符串中的所有匹配结果。

    1
    "1 plus 2 equals 3".match(/\d+/g) // 返回["1", "2", "3"]

如果正则没有设置修饰符g,match()不会全局检索,而是只检索第一个匹配,返回一个数组。数组的第一个元素就是匹配的字符串,余下的元素则是正则表达式中用圆括号括起来的子表达式。

  • 最后一个是split(),可以将调用它的字符串拆分为一个子串组成的数组,使用的分隔符是split()的参数。如:

    1
    "123,456,789".split(","); //返回["123","456","789"];

split()的参数也可以是一个正则表达式,例如可以指定分隔符,允许两边留有任意多的空白符。

1
"1, 2, 3, 4, 5".split(/\s*,\s*/); //返回["1","2","3","4","5"]
用于模式匹配RegExp对象方法

RegExp对象也可以通过RegExp()构造函数生成。它包括一个或者两个字符串参数。第一个参数是正则表达式的内容,第二个参数是标志(可选),例如:g, i, m等。注意,需要转义时用\代替\。

1
var zipcode = new RegExp("\\d{5}", "g");

RegExp对象定义了两个用于执行模式匹配操作的方法。

第一个方就是exec()方法,类似于match()方法。不同于match()的是,exec()方法无论是否有 g 标志,它都只返回同样的数组array。array的第一个元素array[0]储存完全匹配的字符串,随后的元素一次储存与子字符类想匹配的子字符串。当模式有 g 标志的时候,exec()方法执行一次以后,会自动将RegExp对象的一个特殊属性lastIndex置为此次匹配的字符串的最后一个字母的后一个位置。

当同一个正则表达式再次执行的时候,会在lastIndex位置开始查找,而不是0位置开始查找。如果exec()没有找到匹配的字符串,它将自动将lastIndex置为0。这个特殊的方法,可以很方便的循环遍历整个字符串,以找到所有匹配的子字符串。当然,你也可以在找到最后一个匹配子字符串以前的任意时刻将lastIndex置为0,然后用该RegExp对象执行另外的字符串。

1
2
3
4
5
6
7
var pattern = /Java/g;
var text = "JavaScript is more fun than Java!";
var result;
while((result = pattern.exec(text)) != null)
{
alert("Matched '" + result[0] + "'" + " at position " + result.index + "; next search begins at " + pattern.lastIndex);
}

RegExp对象的另外一个执行匹配的方法是test(),它要比exec()简单的多。它只有一个字符串作为唯一的参数,返回true或者在没有找到匹配字符串是返回null。当RegExp有g标志时,test()与exec()对lastIndex执行同样的操作。