14.5 简单模式
要精确地构造所需的正则表达式是一件不容易的事情。灵活运用正则表达式,必须充分了解正则表达式的构造语法。而正则表达式的语法主要是对正则表达式各个元字符功能的描述,接下来的两节将详细描述各个元字符的功能。根据其复杂程度,正则表达式可以分为简单模式和复杂模式。其中,简单模式包括普通字符、特殊字符、字符类以及量词等。
14.5.1
普通字符
普通字符可以是字母、数字、汉字、下划线,以及没有特殊定义的标点符号等。表达式中的普通字符,在匹配一个字符串时,匹配与之相同的字符。
如正则表达式/abc/,abc由普通字符构成。在匹配时,只要在匹配字符串中出现“abc”,即可成功匹配。
特别指出的是,如果是在表达式中表示特殊意义的字符,如“*”、“+”、“{”、“(”、“)”等(这些都有特殊含义,将在下面的章节中解释),那就要在前面加转义符“\”。例如要匹配字符“*”,正则表达式就要写成:/\*/。转义符的特殊字符汇总如表14.4所示。
表14.4 需要用转义符的特殊字符表
|
字符 |
^ |
$ |
( |
) |
{ |
} |
+ |
* |
. |
? |
| |
[ |
] |
|
表示 |
\^ |
\$ |
\( |
\) |
\{ |
\} |
\+ |
\* |
\. |
\? |
\| |
\[ |
\] |
到此,有些读者可能要问,如何匹配转义符“\”呢?确实,转义符“\”也是一个很特殊的字符,而且在显式构造和隐式构造中表示形式也不相同。
如果正则表达式中要匹配原义字符“\”,并且用隐式构造法,那么模式文本中要以“\\”来表示:
var re=/\\/;
若使用显式构造法,因为JavaScript中的字符串的转义字符也是“\”(请参考String对象相关知识),所以必须使用“\\\\”来表示原义字符“\”,如下代码所示。
var re = new RegExp("\\\\");
注意:由于JavaScript中字符串的转义字符也是“\”,所以用显式构造法去创建正则表示式时,如果用到后面的特殊字符或者字符类,如“\d”,就要多加一个“\”,如var re= new RegExp("\\d{5}")正确,而var re1 = new RegExp("\d{5}")则错误。
14.5.2
特殊字符
一些不便书写的特殊字符,如回车换行符、制表符等,也采用在前面加“\”的方法来表示。特殊字符汇总如表14.5所示。
表14.5 特殊字符表
|
字符 |
\t |
\n |
\r |
\f |
\a |
\e |
\v |
\0 |
|
描述 |
制表符 |
换行 |
回车 |
换页 |
alert字符 |
escape字符 |
垂直制表符 |
空字 |
这些特殊的字符还包括:
“\xn”:匹配ASCⅡ码值等于n的字符,n必须是两位的十六进制整数,如“\x65”表示字符A,而\x97表示字符a。
“\un”:匹配Unicode编码等于n的字符,n必须是一个4位的十六进制整数。
“\cX”:匹配X对应的控制字符,如“\cM”表示Ctrl+M表示的控制字符。
14.5.3
字符类
字符类包括:简单类、反向类、范围类、组合类以及预定义类。
简单类:用方括号“[]”来表示单个字符“或”的关系,匹配方括号内任意一个字符。例如正则表达式/[123]/可以匹配“1”、“2”、“3”中的任意一个字符。
注意:如果方括号[]中需要匹配字符“]”,则需要把“]”放在字符串的首位,并加转义符“\”,写成/[\]123]/的形式。
反向类:[^]用来匹配不在括号内的任意字符,恰与简单类相反,故称为反向类。例如表达式/[^abc]/,不匹配“a”、“b”或“c”,可以匹配除这三个字符外的其他任意字符。
注意:绝对不能大意写成/^[]/,那“^”就变成后面要介绍的定位符,表示匹配以括号中任意字符开头的字符串。书写正则表达式一定不可粗心大意。
范围类:[x-y]用来表示一个匹配范围x到y,即可匹配从x到y的任意字符。最常用的就是查找从a到z的任意字符,其表达式可以写成/[a-z]/;匹配任意的数字,表达式可写成/[0-9]/。
范围类可以和反向类结合使用,如表达式/[^a-z]/可以匹配除了a-z范围外的其他任意字符。
注意:如果还要在范围类中匹配“-”字符,那么就应该放在x前或者y后,写成/-x-y/或者/x-y-/。
组合类:即简单类、反向类以及范围类的组合。例如表达式/[a-z0-9\.]/可以匹配a-z的任意字符,也可以匹配0-9的任意数字,还可以匹配特殊字符“.”。
注意:类不能嵌套,即不支持联合类和交叉类。例如:联合类/a-m[p-z]/和交叉类/a-m[^b-e]/在JavaScript中都是非法的。
在JavaScript中,有些常用的类,比如数字、单词字符等,用上面的组合类也能定义,但是定义和使用都很不方便,所以预先做了定义,称为预定义类。
预定义类包括:点. 、\d 、\D 、\s 、\S 、\w 、\W。它们的等价组合类,以及描述汇总情况如表14.6所示。
表14.6 预定义类表
|
预定义类 |
等价的组合类 |
匹配描述 |
|
. |
[^\n\r] |
除了换行和回车之外的任何字符 |
|
\d |
[0-9] |
数字 |
|
\D |
[^0-9] |
非数字 |
|
\s |
[ \t\n\x0B\f\r] |
空白字符,包括空格、制表符、制页符等 |
|
\S |
[^ \t\n\x0B\f\r] |
非空白字符 |
|
\w |
[a-zA-Z_0-9] |
单词字符(字母、数字、下划线) |
|
\W |
[^a-zA-Z_0-9] |
非单词字符(即非字母、数字或者下划线) |
源程序14.8检验用户名是否有效:有效的用户名包含以字母或数字开头,加单词字符,并以数字结尾的子字符串。正则表达式可以表示为/[a-z0-9]\w\d/,若用户输入的字符串能找到正则表达式的匹配,则用户名有效并通过检验,否则用户名无效并弹出警告框。
//源程序14.8
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html140/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Sample Page!</title>
<script language="JavaScript" type="text/javascript">
<!--
function test_zifulei(obj)
{
var username=obj.username.value;
var regx=/[a-z0-9]\w\d/g
//不包含规定字符,用户名无效
if(!regx.test(username))
{
alert("\n用户名检测 : \n\n结果 : 用户名不合法! \n");
obj.username.focus();
}
else
alert("\n用户名检测 : \n\n结果 : 用户名合法! \n");
}
-->
</script>
</head>
<body>
<center>
<p>
用户名合法性检测程序
</p>
<p>
规则:英文字符串+数字
</p>
<form onSubmit="return test_zifulei(this);">
<input type="text" name="username" value="yangshuiqing">
<input type="submit" value="合法性检测">
</form>
</center>
</body>
</html>
程序运行后,结果页面如图14.13所示。
输入用户名“yangshuiqing”,不能成功匹配正则表达式/[a-z0-9]\w\d/,则用户名非法,弹出警告框如图14.14所示。
输入用户名“yangshuiqing123”,成功匹配正则表达式/[a-z0-9]\w\d/,则用户名合法,弹出警告框如图14.15所示。

图14.13 原始页面 图14.14 用户名“yangshuiqing” 图14.15 用户名“yangs-
不能匹配正则表达式 huiqing123”有效
14.5.4
量词
英文中量词是用来表示个数,单数用a或者an,复数用these或者those。在正则表达式中,量词也是用来限制某些匹配字符个数的,所以也称为限定符。
正则表达式的量词表示形式总结如表14.7所示。
表14.7 量词表
|
限 定 符 |
作 用 |
举 例 |
|
* |
出现0次或连续多次 |
/a*b/可以匹配“b”,“aab”,“aaab”... |
|
+ |
出现至少一次 |
/a+b/可以匹配“ab”,“aab”,“aaab”... |
|
? |
出现0次或者一次 |
/a[cd]?/可以匹配“a”,“ac”,“ad” |
|
{n} |
连续出现n次(=n) |
/\d{2}/ 相当于“\d\d”;“b{5}”相当于“bbbbb” |
|
{n,} |
连续出现至少n次(>=n) |
/\w\d{2,}/可以匹配“a12”,“b456”,“c54786”... |
|
{n,m} |
连续出现至少n次,至多m次(>=n,<=m) |
/ba{1,3}/可以匹配“ba”或“baa”或“baaa” |
量词之间可以互相等价表示,如?={0,1}、*={0,}、+={1,},读者可以自行选择,但以书写简洁为原则。正则表达式之间是互通的,所以任何正则表达式的写法是不唯一的。
量词往往在一个表达式中联合使用,再来看些例子。
正则表达式/\$\d+\.?\d*/可以匹配带$开头的物品价格。当字符串为“猪肉的价格为$13.5”时,那么该正则表达式就能正确地匹配$13.5。
再如正则表达式/\d{3}-\d{7-8}/可以匹配像020-1578964 或者 021-84579654这样开头是三位后面跟着七位或八位数字的字符串,类似于表示电话号码的正则表达式,但不精确,学习“候选符”相关内容后再来精确表示电话号码的正则表达式。
在上面量词的介绍中,除了量词{n}外,其他量词匹配的次数都是不精确的。正则表达式在模式匹配时,就出现了返回最多的匹配还是最少的匹配的问题,为此,正则表达式引入贪婪和非贪婪两种匹配模式,下面分别予以介绍。
14.5.5
贪婪模式
根据匹配字符串以及表达式尽可能多地进行匹配,称为贪婪匹配模式,简称贪婪模式。正则表达式的默认匹配模式为贪婪模式。
例如,正则表达式为/a\d+/,匹配字符串为“a154222222”,则/d+匹配完整的154222222,虽然它也可以只匹配其中的一部分,如15422。
再如,正则表达式/fo{2,}/,匹配字符串为“fooooood”,那么o{2,}就会匹配完6个“o”,虽然它也可以只匹配2个或者4个“o”。
14.5.6
非贪婪模式
与贪婪模式相对应,根据匹配字符串以及表达式尽可能少地进行匹配,称为非贪婪匹配模式,简称非贪婪模式。
其使用方法就是在修饰匹配次数的特殊符号后再加上一个“?”号,如“*?”、“+?”、“{n,}?”、“{n,m}?”,当然在量词{n}后加“n”也可以,但意义不大。值得注意的是,并没有在量词“?”后面加“?”的写法。
例如正则表达式为/a\d+?/,匹配字符串为“a154222222”,那么其中的/d+就只匹配子串“1”;再如正则表达式/fo{2,}?/,匹配字符串为“fooooood”,那么其中的o{2,}就只匹配子串“oo”。
14.5.7
简单模式综合举例
在实际应用中经常需要验证手机号码的合法性,一般使用正则表达式/^(\+86)?13\d{9}$/来检验。考虑以“13”开头的手机号码,同时如果跨中继站时需加“+86”(cn)。至于新号段“158”和“159”,可扩展以上正则表达式进行检验。程序代码如源程序14.9所示。
//源程序14.9
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html140/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Sample Page!</title>
<script language="JavaScript" type="text/javascript">
<!--
//使用正则表达式验证手机号码
function isMobil(obj)
{
var str=obj.mobilenum.value;
var patrn=/^(\+86)?13\d{9}$/;
var msg="\n使用正则表达式验证手机号码 :\n\n";
msg+="手机号码 : " +str+"\n";
if (!patrn.exec(str))
{
msg+="验证结果 : 手机号码不合法!\n";
alert(msg);
return false;
}
else
{
msg+="验证结果 : 手机号码合法!\n";
alert(msg);
return true;
}
}
-->
</script>
</head>
<body>
<br>
<center>
<p>
使用正则表达式验证手机号码合法性
</p>
<form onSubmit="return isMobil(this);">
<input type="text" name="mobilenum">
<input type="submit" value="确定">
</form>
</center>
</body>
</html>
程序运行后,在原始页面的文本输入框内输入“13548968549”或“+8613548968549”,弹出“手机号码合法!”的警告框,如图14.16所示。
如果输入“+10013548968549”等格式不正确的手机号码,则弹出“手机号码不合法!”的警告框,如图14.17所示。

图14.16 输入正确格式的手机号码 图14.17 输入格式错误的手机号码
在实际应用中,还可以根据目标手机号码的各小段信息判断该手机号码的归属地、号码类型等信息,并返回更为丰富的结果。同样,可先提取目标电话号码中的国家代码(如中国为+86),然后根据该代码判断手机号码所属的国家。
注意:在正则表达式/^(\+86)?13\d{9}$/中,^与$是定位符,起到开头结尾匹配作用,将在第14.6.7节中详细介绍。而(\+86)?表示“+86”字符串可以出现0次或1次,也将在第14.6.1节中详细介绍。






