JavaScript正则表达式详解(一)正则表达式入门

JavaScript正则表达式是很多JavaScript开发人员比较头疼的事情,也很多人不愿意学习,只是必要的时候上网查一下就可以啦~本文中详细的把JavaS

JavaScript正则表达式是很多JavaScript开发人员比较头疼的事情,也很多人不愿意学习,只是必要的时候上网查一下就可以啦~本文中详细的把JavaScript正则表达式的用法进行了列表,希望对于大家学习JavaScript正则表达式有一定的帮助。

建立正则表达式对象语法

re = new RegExp(/pattern/[flags])

flags 参数说明:

  • g (全文查找出现的所有 pattern
  • i (忽略大小写)
  • m (多行查找)
普通字符描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如,’n’ 匹配字符 “n”。’\n’ 匹配一个换行符。序列 ‘\\’ 匹配 “\” 而 “\(” 则匹配 “(”。
. 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用象 ‘[.\n]‘ 的模式。
x|y 匹配 x 或 y。例如,’z|food’ 能匹配 “z” 或 “food”。’(z|f)ood’ 则匹配 “zood” 或 “food”。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]‘ 可以匹配 “plain” 中的 ‘a’。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]‘ 可以匹配 “plain” 中的’p’。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,’[a-z]‘ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,’[^a-z]‘ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]‘。
\W 匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]‘。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, ‘\x41′ 匹配 “A”。’\x041′ 则等价于 ‘\x04′ & “1″。正则表达式中可以使用 ASCII 编码。.
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,’(.)\1′ 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若? n 和 m 均为八进制数字 (0-7),则 \nm将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

 

特殊字符说明
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 \$。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
. 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
\ 将下一个字符标记为或特殊字符、或原义字符、或后向引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\' 匹配 "\",而 '\(' 则匹配 "("。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用\^。
{ 标记限定符表达式的开始。要匹配 {,请使用 \{。
| 指明两项之间的一个选择。要匹配 |,请使用 \|。

 

非打印字符含义
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
n 匹配一个换行符。等价于 x0a 和 cJ。
r 匹配一个回车符。等价于 x0d 和 cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [?\f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^?\f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

 

限定符描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。 * 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,”do(es)?” 可以匹配 “do” 或 “does” 中的”do” 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*’。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, “o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。

 

定位符描述
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。
\B 匹配非单词边界。

 


 

一、正则表达式入门

什么是正则表达式?

这个问题可以参见:“正则表达式30分钟入门教程”,很多编程语言都支持正则表达式,本文仅仅讨论JavaScript中的正则表达式。

创建一个正则表达式

第一种方法:

var reg = /pattern/;

第二种方法:

var reg = new  RegExp('pattern');

正则表达式的exec()方法简介(为方便下面学习测试正则表达式用!!!)

语法:

reg.exec(str);

其中str为要执行正则表达式的目标字符串。

例如:

<script  type="text/javascript">
var reg = /test/;
var str = 'testString';
var result = reg.exec(str);
alert(result);
</script>

将会输出test,因为正则表达式reg会匹配str(‘testString’)中的’test’子字符串,并且将其返回。

我们使用下面的函数来做匹配正则的练习:

function execReg(reg,str){
	var result = reg.exec(str);
	alert(result);
}

函数接受一个正则表达式参数reg和一个目标字符串参数str,执行之后会alert出正则表达式与字符串的匹配结果。

用这个函数测试上面的例子就是:

<script type="text/javascript">
function execReg(reg, str) {
	var result = reg.exec(str);
	alert(result);
}
var reg = /test/;
var str = 'testString';
execReg(reg,str);
</script>

上面的例子用正则里的test去匹配字符串里的test,实在是很无聊,同样的任务用indexOf方法就可以完成了。用正则,自然是要完成更强大的功能。

一片两片三四片,落尽正则全不见(开始正则表达式简介)

上面的小标题翻译成正则就是{1},{2},{3,4},{1,}。

c{n}

{1}表示一个的意思。

/c{1}/只能匹配一个c。

/c{2}/则会匹配两个连续的c。

以此类推,

/c{n}/则会匹配n个连续的c。

看下面的例子:

reg = /c{1}/;
str = 'cainiao';
execReg(reg, str);

返回结果c

reg = /c{2}/;
str = 'cainiao';
execReg(reg, str);

返回结果null,表示没有匹配成功。

reg = /c{2}/;
str = 'ccVC果冻爽';
execReg(reg, str);

返回结果cc。

c{m,n}

c{3,4}的意思是,连续的3个c或者4个c。

例如

reg = /c{3,4}/;
str = 'ccVC果冻爽';
execReg(reg, str);

返回结果null,表示没有匹配成功。

reg = /c{3,4}/;
str = 'cccTest';
execReg(reg, str);

结果返回ccc。

reg = /c{3,4}/;
str = 'ccccTest';
execReg(reg, str);

结果返回cccc,这表明正则会尽量多品牌,可3可4的时候它会选择多匹配一个。

reg = /c{3,4}/;
str = 'cccccTest';
execReg(reg, str);

仍然只匹配4个c。

由以上例子可以推断出,c{m,n}表示m个到n个c,且m小于等于n。

c{n,}

c{1,}表示1个以上的c。例如:

reg = /c{1,}/;
str = 'cainiao';
execReg(reg, str);

结果返回c。

reg = /c{1,}/;
str = 'cccccTest';
execReg(reg, str);

返回ccccc,再次说明了正则表达式会尽量多地匹配。

reg = /c{2,}/;
str = 'cainiao';
execReg(reg, str);

结果返回null,c{2,}表示2个以上的c,而cainiao中只有1个c。

由以上例子可知,c{n,}表示最少n个c,最多则不限个数。

*,+,?

*表示0次或者多次,等同于{0,},即

c* 和 c{0,} 是一个意思。

+表示一次或者多次,等同于{1,},即

c+ 和 c{1,} 是一个意思。

最后,?表示0次或者1次,等同于{0,1},即

c? 和 c{0,1} 是一个意思。

贪心与非贪心

人都是贪婪的,正则也是如此。我们在例子reg = /c{3,4}/;str=’ccccTest’;的例子中已经看到了,能匹配四个的时候,正则绝对不会去匹配三个。上面所介绍的所有的正则都是这样,只要在合法的情况下,它们会尽量多去匹配字符,这就叫做贪心模式

如果我们希望正则尽量少地匹配字符,那么就可以在表示数字的符号后面加上一个?。组成如下的形式:

{n,}?, *?, +?, ??, {m,n}?

同样来看一个例子:

reg = /c{1,}?/;
str = 'ccccc';
execReg(reg, str);

返回的结果只有1个c,尽管有5个c可以匹配,但是由于正则表达式是非贪心模式,所以只会匹配一个。

/^开头,结尾$/

^表示只匹配字符串的开头。看下面的例子:

reg = /^c/;
str = '维生素c';
execReg(reg, str);

结果为null,因为字符串‘维生素c’的开头并不是c,所以匹配失败。

reg = /^c/;
str = 'cainiao';
execReg(reg, str);

这次则返回c,匹配成功,因为cainiao恰恰是以c开头的。

与^相反,$则只匹配字符串结尾的字符,同样,看例子:

reg = /c$/;
str = 'cainiao';
execReg(reg, str);

返回null,表示正则表达式没能在字符串的结尾找到c这个字符。

reg = /c$/;
str = '维生素c';
execReg(reg, str);

这次返回的结果是c,表明匹配成功。

 点’.’

‘.’会匹配字符串中除了换行符\n之外的所有字符,例如

reg = /./;
str = 'cainiao';
execReg(reg, str);

结果显示,正则匹配到了字符c。

reg = /./;
str = 'blueidea';
execReg(reg, str);

这次是b。

reg = /.+/;
str = 'blueidea——经典论坛  好_。';
execReg(reg, str);

结果是“blueidea——经典论坛 好_。“也就是说所有的字符都被匹配掉了,包括一个空格,一个下滑线,和一个破折号。

reg = /.+/;
reg = /.+/;
str = 'bbs.blueidea.com';
execReg(reg, str);

同样,直接返回整个字符串——bbs.blueidea.com,可见”.”也匹配”.”本身。

reg = /^./;
str = '\ncainiao';
execReg(reg, str);

结果是null,终于失败了,正则要求字符串的第一个字符不是换行,但是恰恰字符是以\n开始的。

二选一,正则表达式中的或,“|“

b|c表示,匹配b或者c。

例如:

reg = /b|c/;
str = 'blueidea';
execReg(reg, str);

结果是b。

reg = /b|c/;
str = 'cainiao';
execReg(reg, str);

结果是c。

reg = /^b|c.+/;
str = 'cainiao';
execReg(reg, str);

匹配掉整个cainiao。

reg = /^b|c.+/;
str = 'bbs.blueidea.com';
execReg(reg, str);

结果只有一个b,而不是整个字符串。因为上面正则表达式的意思是,匹配开头的b或者是c.+。

括号

reg = /^(b|c).+/;

str = 'bbs.blueidea.com';
execReg(reg, str);

这次的结果是整个串bbs.blueidea.com,机上上面的括号这后,这个正则的意思是,如果字符串的开头是b或者c,那么匹配开头的b或者c以及其后的所有的非换行字符。

如果你也实验了的话,会发现返回的结果后面多出来一个“,b“,这是()内的b|c所匹配的内容。我们在正则表达式内括号里写的内容会被认为是子正则表达式,所匹配的结果也会被记录下来供后面使用。我们暂且不去理会这个特性。

字符集合[abc]

[abc]表示a或者b或者c中的任意一个字符。例如:

reg = /^[abc]/;
str='bbs.blueidea.com';
execReg(reg,str);

返回结果是b。

reg = /^[abc]/;
str='test';
execReg(reg,str);

这次的结果就是null了。

我们在字字符集合中使用如下的表示方式:[a-z],[A-Z],[0-9],分别表示小写字母,大写字母,数字。例如:

reg =  /^[a-zA-Z][a-zA-Z0-9_]+/;
str='test';
execReg(reg,str);

结果是整个test,正则的意思是开头必须是英文字母,后面可以是英文字母或者数字以及下划线。

反字符集合[^abc]

^在正则表达式开始部分的时候表示开头的意思,例如/^c/表示开头是c;但是在字符集和中,它表示的是类似“非“的意思,例如[^abc]就表示不能是a,b或者c中的任何一个。例如:

reg = /[^abc]/;
str='blueidea';
execReg(reg,str);

返回的结果是l,因为它是第一个非abc的字符(即第一个b没有匹配)。同样:

reg = /[^abc]/;
str='cainiao';
execReg(reg,str);

则返回i,前两个字符都是[abc]集合中的。

由此我们可知:[^0-9]表示非数字,[^a-z]表示非小写字母,一次类推。

边界与非边界

\b表示的边界的意思,也就是说,只有字符串的开头和结尾才算数。例如/\bc/就表示字符串开始的c或者是结尾的c。看下面的例子:

reg = /\bc/;
str='cainiao';
execReg(reg,str);

返回结果c。匹配到了左边界的c字符。

reg = /\bc/;
str='维生素c';
execReg(reg,str);

仍然返回c,不过这次返回的是右侧边界的c。

reg = /\bc/;
str='bcb';
execReg(reg,str);

这次匹配失败,因为bcb字符串中的c被夹在中间,既不在左边界也不再右边界。

与\b对应\B表示非边界。例如:

reg = /\Bc/;
str='bcb';
execReg(reg,str);

这次会成功地匹配到bcb中的c,。然而

reg = /\Bc/;
str='cainiao';
execReg(reg,str);

则会返回null。因为\B告诉正则,只匹配非边界的c。

数字与非数字

\d表示数字的意思,相反,\D表示非数字。例如:

reg = /\d/;
str='cainiao8';
execReg(reg,str);

返回的匹配结果为8,因为它是第一个数字字符。

reg = /\D/;
str='cainiao8';
execReg(reg,str);

返回c,第一个非数字字符。

空白

\f匹配换页符,\n匹配换行符,\r匹配回车,\t匹配制表符,\v匹配垂直制表符。

\s匹配单个空格,等同于[\f\n\r\t\v]。例如:

reg = /\s.+/;
str='This is a test  String.';
execReg(reg,str);

返回“is a test String.”,正则的意思是匹配第一个空格以及其后的所有非换行字符。

同样,\S表示非空格字符。

reg = /\S+/;
str='This is a test  String.';
execReg(reg,str);

匹配结果为This,当遇到第一个空格之后,正则就停止匹配了。

单词字符

\w表示单词字符,等同于字符集合[a-zA-Z0-9_]。例如:

reg = /\w+/;
str='blueidea';
execReg(reg,str);

返回完整的blueidea字符串,因为所有字符都是单词字符。

reg = /\w+/;
str='.className';
execReg(reg,str);

结果显示匹配了字符串中的className,只有第一个“.”——唯一的非单词字符没有匹配。

reg = /\w+/;
str='中文如何?';
execReg(reg,str);

试图用单词字符去匹配中文自然行不通了,返回null。

\W表示非单词字符,等效于[^a-zA-Z0-9_]

reg = /\W+/;
str='中文如何?';
execReg(reg,str);

返回完整的字符串,因为,无论是中文和“?”都算作是非单词字符。

反向引用

形式如下:/(子正则表达式)\1/

依旧用例子来说明:

1.

reg = /\w/;
str='blueidea';
execReg(reg,str);

返回b。

2.

reg = /(\w)(\w)/;
str='blueidea';
execReg(reg,str);

返回bl,b,l

bl是整个正则匹配的内容,b是第一个括号里的子正则表达式匹配的内容,l是第二个括号匹配的内容。

3.

reg = /(\w)\1/;
str='blueidea';
execReg(reg,str);

则会返回null。这里的“\1”就叫做反向引用,它表示的是第一个括号内的字正则表达式匹配的内容。在上面的例子中,第一个括号里的(\w)匹配了b,因此“\1”就同样表示b了,在余下的字符串里自然找不到b了。

与第二个例子对比就可以发现,“\1”是等同于“第1个括号匹配的内容”,而不是“第一个括号的内容”。

reg = /(\w)\1/;
str='bbs.blueidea.com';
execReg(reg,str);

这个正则则会匹配到bb。

同样,前面有几个子正则表达式我们就可以使用几个反向引用。例如:

reg = /(\w)(\w)\2\1/;
str='woow';
execReg(reg,str);

会匹配成功,因为第一个括号匹配到w,第二个括号匹配到o,而\2\1则表示ow,恰好匹配了字符串的最后两个字符。

括号(2)

前面我们曾经讨论过一次括号的问题,见下面这个例子:

reg = /^(b|c).+/;
str='bbs.blueidea.com';
execReg(reg,str);

这个正则是为了实现只匹配以b或者c开头的字符串,一直匹配到换行字符,但是。上面我们已经看到了,可以使用“\1”来反向引用这个括号里的子正则表达式所匹配的内容。而且exec方法也会将这个字正则表达式的匹配结果保存到返回的结果中。

不记录子正则表达式的匹配结果

使用形如(?:pattern)的正则就可以避免保存括号内的匹配结果。例如:

reg = /^(?:b|c).+/;
str='bbs.blueidea.com';
execReg(reg,str);

可以看到返回的结果不再包括那个括号内的字正则表达式多匹配的内容。

同理,反向引用也不好使了:

reg = /^(b|c)\1/;
str='bbs.blueidea.com';
execReg(reg,str);

返回bb,b。bb是整个正则表达式匹配的内容,而b是第一个子正则表达式匹配的内容。

reg = /^(?:b|c)\1/;
str='bbs.blueidea.com';
execReg(reg,str);

返回null。由于根本就没有记录括号内匹配的内容,自然没有办法反向引用了。

正向预查

形式:(?=pattern)

所谓正向预查,意思就是:要匹配的字符串,后面必须紧跟着pattern!

我们知道正则表达式/cainiao/会匹配cainiao。同样,也会匹配cainiao9中的cainiao。但是我们可能希望,cainiao只能匹配cainiao8中的菜鸟。这时候就可以像下面这样写:/cainiao(?=8)/,看两个实例:

reg = /cainiao(?=8)/;
str='cainiao9';
execReg(reg,str);

返回null。

reg = /cainiao(?=8)/;
str='cainiao8';
execReg(reg,str);

匹配cainiao。

需要注意的是,括号里的内容并不参与真正的匹配,只是检查一下后面的字符是否符合要求而已,例如上面的正则,返回的是cainiao,而不是cainiao8。

再来看两个例子:

reg = /blue(?=idea)/;
str='blueidea';
execReg(reg,str);

匹配到blue,而不是blueidea。

reg = /blue(?=idea)/;
str='bluetooth';
execReg(reg,str);

返回null,因为blue后面不是idea。

reg = /blue(?=idea)/;
str='bluetoothidea';
execReg(reg,str);

同样返回null。

?!

形式(?!pattern)和?=恰好相反,要求字符串的后面不能紧跟着某个pattern,还拿上面的例子:

reg = /blue(?!idea)/;
str='blueidea';
execReg(reg,str);

返回null,因为正则要求,blue的后面不能是idea。

reg = /blue(?!idea)/;
str='bluetooth';
execReg(reg,str);

则成功返回blue。

匹配元字符

首先要搞清楚什么是元字符呢?我们之前用过*,+,?之类的符号,它们在正则表达式中都有一定的特殊含义,类似这些有特殊功能的字符都叫做元字符。例如

reg = /c*/;

表示有任意个c,但是如果我们真的想匹配’c*’这个字符串的时候怎么办呢?只要将*转义了就可以了,如下:

reg = /c\*/;
str='c*';
execReg(reg,str);

返回匹配的字符串:c*。

同理,要匹配其他元字符,只要在前面加上一个“\”就可以了。

正则表达式的修饰符

全局匹配,修饰符g

形式:/pattern/g

例子:reg = /b/g;

后面再说这个g的作用。先看后面的两个修饰符。

不区分大小写,修饰符i

形式:/pattern/i

例子:

var reg = /b/;
var str = 'BBS';
execReg(reg,str);

返回null,因为大小写不符合。

var reg = /b/i;
var str = 'BBS';
execReg(reg,str);

匹配到B,这个就是i修饰符的作用了。

行首行尾,修饰符m

形式:/pattern/m

m修饰符的作用是修改^和$在正则表达式中的作用,让它们分别表示行首和行尾。例如:

var reg = /^b/;
var str = 'test\nbbs';
execReg(reg,str);

匹配失败,因为字符串的开头没有b字符。但是加上m修饰符之后:

var reg = /^b/m;
var str = 'test\nbbs';
execReg(reg,str);

匹配到b,因为加了m修饰符之后,^已经表示行首,由于bbs在字符串第二行的行首,所以可以成功地匹配。

 

 

延伸阅读:

JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解