前面几节讲解了如何在 JavaScript 中使用正则表达式,以及如何执行匹配,本节就来讲一下正则表达式的具体语法。
正则表达式是一种通用的工具,在 JavaScript、PHP、Java、Python、C++ 等几乎所有的编程语言中都能使用;但是,不同编程语言对正则表达式语法的支持不尽相同,有的编程语言支持所有的语法,有的仅支持一个子集。本节讲到的正则表达式语法适用于 JavaScript。
正则表达式的语法体现在字符模式上。字符模式是一组特殊格式的字符串,它由一系列特殊字符和普通字符构成,其中每个特殊字符都包含一定的语义和功能。
根据正则表达式语法规则,大部分字符仅能够描述自身,这些字符被称为普通字符,如所有的字母、数字等。
元字符就是拥有特动功能的特殊字符,大部分需要加反斜杠进行标识,以便于普通字符进行区别,而少数元字符,需要加反斜杠,以便转译为普通字符使用。JavaScript 正则表达式支持的元字符如表所示。
元字符 | 描述 |
---|---|
. | 查找单个字符,除了换行和行结束符 |
\w | 查找单词字符 |
\W | 查找非单词字符 |
\d | 查找数字 |
\D | 查找非数字字符 |
\s | 查找空白字符 |
\S | 查找非空白字符 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
\0 | 查找 NUL字符 |
\n | 查找换行符 |
\f | 查找换页符 |
\r | 查找回车符 |
\t | 查找制表符 |
\v | 查找垂直制表符 |
\xxx | 查找以八进制数 xxxx 规定的字符 |
\xdd | 查找以十六进制数 dd 规定的字符 |
\uxxxx | 查找以十六进制 xxxx规定的 Unicode 字符 |
表示字符的方法有多种,除了可以直接使用字符本身外,还可以使用 ASCII 编码或者 Unicode 编码来表示。
下面使用 ASCII 编码定义正则表达式直接量。
var r = /\x61/; var s = "JavaScript"; var a = s.match(s);
由于字母 a 的 ASCII 编码为 97,被转换为十六进制数值后为 61,因此如果要匹配字符 a,就应该在前面添加“\x”前缀,以提示它为 ASCII 编码。
除了十六进制外,还可以直接使用八进制数值表示字符。
var r = /\141/; var s = "JavaScript"; var a = s.match(r);
使用十六进制需要添加“\x”前缀,主要是为了避免语义混淆,而八进制则不需要添加前缀。
ASCII 编码只能够匹配有限的单字节字符,使用 Unicode 编码可以表示双字节字符。Unicode 编码方式:“\u”前缀加上 4 位十六进制值。
var r = "/\u0061/"; var s = "JavaScript"; var a = s.match(s);
在 RegExp() 构造函数中使用元字符时,应使用双斜杠。
var r = new RegExp("\\u0061");
RegExp() 构造函数的参数只接受字符串,而不是字符模式。在字符串中,任何字符加反斜杠还表示字符本身,如字符串“\u”就被解释为 u 本身,所以对于“\u0061”字符串来说,在转换为字符模式时,就被解释为“u0061”,而不是“\u0061”,此时反斜杠就失去转义功能。解决方法:在字符 u 前面加双反斜杠。
在正则表达式语法中,放括号表示字符范围。在方括号中可以包含多个字符,表示匹配其中任意一个字符。如果多个字符的编码顺序是连续的,可以仅指定开头和结尾字符,省略中间字符,仅使用连字符~
表示。如果在方括号内添加脱字符^
前缀,还可以表示范围之外的字符。例如:
字符范围遵循字符编码的顺序进行匹配。如果将要匹配的字符恰好在字符编码表中特定区域内,就可以使用这种方式表示。
如果匹配任意 ASCII 字符:
var r = /[\u0000-\u00ff]/g;
如果匹配任意双字节的汉字:
var r = /[^\u0000-\u00ff]/g;
如果匹配任意大小写字母和数字:
var r = /[a-zA-Z0-9]/g;
使用 Unicode 编码设计,匹配数字:
var r = /[\u0030-\u0039]/g;
使用下面字符模式可以匹配任意大写字母:
var r = /[\u0041-\u004A]/g;
使用下面字符模式可以匹配任意小写字母:
var r = /[\u0061-\u007A]/g;
在字符范围内可以混用各种字符模式。
var s = "abcdez"; //字符串直接量 var r = /[abce-z]/g; //字符a、b、c,以及从e~z之间的任意字符 var a = s.match(r); //返回数组["a","b","c","e","z"]
在中括号内不要有空格,否则会误解为还要匹配空格。
var r = /[0-9]/g;
字符范围可以组合使用,以便设计更灵活的匹配模式。
var s = "abc4 abd6 abe3 abf1 abg7"; //字符串直接量 var r = /ab[c-g][1-7]/g; //前两个字符为ab,第三个字符为从c到g,第四个字符为1~7的任意数字 var a = s.match(r); //返回数组["abc4","abd6","abe3","abf1","abg7"]
使用反义字符范围可以匹配很多无法直接描述的字符,达到以少应多的目的。
var r = /[^0123456789]/g;
在这个正则表达式中,将会匹配除了数字以外任意的字符。反义字符类比简单字符类的功能更强大和实用。
选择匹配类似于 JavaScript 的逻辑与运算,使用竖线|
描述,表示在两个子模式的匹配结果中任选一个。例如:
1) 匹配任意数字或字母
var r = /\w+|\d+/;
2) 可以定义多重选择模式。设计方法:在多个子模式之间加入选择操作符。
var r = /(abc)|(efg)|(123)|(456)/;
为了避免歧义,应该为选择操作的多个子模式加上小括号。
设计对提交的表单字符串进行敏感词过滤。先设计一个敏感词列表,然后使用竖线把它们连接在一起,定义选择匹配模式,最后使用字符串的 replace() 方法把所有敏感字符替换为可以显示的编码格式。代码如下:
var s = ''; //待过滤的表单提交信息 var r = /\'|\"|\<|\>/gi; //过滤敏感字符的正则表达式 function f() { //替换函数 ////把敏感字符替换为对应的网页显示的编码格式 return "" + arguments[0].charCodeAt(0) + ";"; } var a =s.replace(r,f); //执行过滤替换 document.write(a); //在网页中显示正常的字符信息 console.log(a);
显示结果如下:
在正则表达式语法中,定义了一组重复类量词,如表所示。它们定义了重复匹配字符的确数或约数。
量词 | 描述 |
---|---|
n+ | 匹配任何包含至少一个 n 的字符串 |
n* | 匹配任何包含零个或多个 n 的字符串 |
n? | 匹配任何包含零个或一个 n 的字符串 |
n{x} | 匹配包含 x 个 n 的序列的字符串 |
n{x,y} | 匹配包含最少 x 个、最多 y 个 n 的序列的字符串 |
n{x,} | 匹配包含至少 x 个 n 的序列的字符串 |
下面结合示例进行演示说明,先设计一个字符串:
var s = "ggle gogle google gooogle goooogle gooooogle goooooogle gooooooogle goooooooogle";
1) 如果仅匹配单词 ggle 和 gogle,可以设计:
var r = /go?gle/g; var a = s.match(r);
量词?
表示前面字符或子表达式为可有可无,等效于:
var r = /go{0,1}gle/g; var a = s.match(r);
2) 如果匹配第 4 个单词 gooogle,可以设计:
var r = /go{3}gle/g; var a = s.match(r);
等效于:
var r = /gooogle/g; var a = s.match(r);
3) 如果匹配第 4 个到第 6 个之间的单词,可以设计:
var r = /go{3,5}gle/g; var a = s.match(r);
4) 如果匹配所有单词,可以设计:
var r = /go*gle/g; var a = s.match(r);
量词*
表示前面字符或表达式可以不出现,或者重复出现任意多次。等效于:
var r = /go(0,)gle/g; var a = s.match(r);
5) 如果匹配包含字符“o”的所有词,可以设计:
var r = /go+gle/g; var a = s.match(r);
量词+
表示前面字符或子表达式至少出现 1 次,最多重复次数不限。等效于:
var r = /go{1,}gle/g; var a = s.match(r);
重复类量词总是出现在它们所作用的字符或子表达式后面。如果想作用于多个字符,需要使用小括号把它们包裹在一起形成一个子表达式。
重复类量词都具有贪婪性,在条件允许的前提下,会匹配尽可能多的字符。
越是排在左侧的重复类量词匹配优先级越高。下面示例显示当多个重复类量词同时满足条件时,会在保证右侧重复类量词最低匹配次数基础上,使最左侧的重复类量词尽可能占有所有字符。
var s = ""; var r = /(<.*>)(<.*>)/ var a = s.match(r); //左侧表达式匹配" " console.log(a[1]); console.log(a[2]); //右侧表达式匹配“