困于JavaScript的正则表达式
前言
为什么说是困于呢?原因很简单啦,因为js的正则表达式语法是基于Perl5语言,但是ECMAScript只是支持里其中的一部分语法,不过,已经有了这部分的支持就已经足够js的使用了,毕竟需要前端进行匹配的情况并不难也不多。我之前学习PHP的时候,有了解过正则,但没仔细深入。这篇文章会讲述两个部分,一个是基于js的正则基础规则(深入的,本宝宝也不明白),另一个是介绍在js中是如何使用正则匹配的。
基于js的正则基础规则
-
直接量字符
什么叫直接量字符呢?我的理解是,正则表达式中的所有字母和数字都是直接按照字面的含义进行匹配的,这叫直接量字符,还有另外一种就是通过 反斜杠 \ 作为前缀的转义字符,例如我们熟知的换行符\n,以下是一些可能使用到的直接量字符表
常用直接量字符表
字符 | 匹配内容 | 注释 |
---|---|---|
字母和数字 | 自己本身 | |
\t | 水平制表符 | |
\n | 换行符 | |
\v | 垂直制表符 | |
\f | 换页符 | |
\r | 回车符 | |
\0 | NUL字符 | 也就是null |
这表格并不完整,但是,其实除了第一个「字母和数字」是有用的以外,其它用的很少。
在正则表达式中,许多的标点符号是有特殊含义的,它们并不想字母和数字一样,直接进行字面意思的匹配。例如,你想要匹配一个 点. ,但是如果你在正则表达式中直接写点的话,会发现其它乱七八糟的东西也会被匹配上,这时候就要记住使用闪亮的 反斜杠 \ 了,把它加在你要匹配的符号前面,就能消除符号对于正则表达式的特殊含义,如 \ . ,就可以了。
有特殊含义的符号有 ^ $ . * + ? = ! : | \ / ( ) [ ] { }
当然,如果你记不住的话,你也可以在所有你想要匹配的标点符号前加上闪亮的 反斜杠 \ ,这样就可以避免出错了。
-
字符类
字符类就是将直接量字符单独放进方括号内,例如这样[a,b,\t],意思是匹配a或b或水平制表符。以下是常用字符类的表格
常用字符类表
字符 | 匹配内容 | 注释 |
---|---|---|
[a,b] | a或者是b | 只匹配方括号里的一个 |
[^a,b] | 除了a和b的其它内容 | 其它内容里面包含了&*^之类的乱七八糟的字符 |
. | 除了换行符和unicode终止符意外的其它字符 | |
\w | 等价于[a-zA-Z0-9_] | 注意最后还包含了一个闪亮的下划线_ |
\W | 等价于[^a-zA-Z0-9_] | |
\d | 任何ASCII数字,等价与[0-9] | 你可以完美的忽略ASCII这东西 |
\D | 任何除ASCII数字以外的字符,等价于[^0-9] | |
\s | 任何unicode的空白符 | |
\S | 任何非unicode空白符的字符 | 注意,\W 和\S是不一样的 |
这个表格的内容都挺常用的,如果可以的话,能把这些字符类都记下来就最好不过了,如果记不下来,那最简单的[a-zA-Z0-9_]、[^a-zA-Z0-9_]用法,总该要会使用吧。
注:js的犀牛书里边\w等价于[a-zA-Z0-9],但是我查了网上的资料,又进行了测试,其实里面应该包含了下划线的,也就是应该等价于[a-zA-Z0-9_]。话说,我的犀牛书应该是正版的啊,怎么会犯这样的错误......
-
重复字符
这种字符就是为了上面的直接量字符和字符类提供重复服务的标记。例如,我们现在已经知道了\d表示的是一个0到9中的某个数字,但是,如果我们想要表示的是两个数字呢?\d\d呗,那十个呢?额......放心啦,伟大的程序员在设计的时候肯定就已经想到这些问题了。我们可以用\d{10}来完美的匹配十个数字。这就是重复字符的用法啦
常用重复字符表
ps:重复字符是作用于其前一个直接量字符或字符类的
字符 | 含义 | 例子 | 注释 |
---|---|---|---|
{n,m} | n<=重复匹配次数<=m | \d{1,4} | 由于\d是匹配一个数字,所以总体来说是匹配1到4个数字 |
{n,} | n<=重复匹配次数 | \d{3,} | 匹配3个以上数字 |
{n} | 重复匹配次数=n | \d{3} | 匹配3个数字 |
? | 重复匹配次数0次或1次,等价与{0,1} | \d? | 匹配0个或这是1个数字 |
+ | 1<=重复匹配次数,等价与{1,} | \d+ | 匹配1个或或者是更多数字 |
* | 重复匹配0次或多次,等价于{0,} | \d* | 匹配0个或者是多个数字 |
还有一个概念是使用“?”进行非贪婪性的重复,如果对正则的要求不高,这个知识点可以跳过。使用上表的重复字符进行重复匹配的时候,是尽可能多的匹配。如有正则\b+和一组数字1231243,正则可以匹配该串数字里的任意一组,如1、12、123等等,这就是贪婪性的重复。但是使用\b+?作为正则的话,就会在匹配了第一个数字1之后停止匹配。在待匹配的字符后面加一个“?”,就可以开启非贪婪匹配了,如“ *? ”。不过,我们必须要在“整个表达式匹配成功”的前提下,贪婪模式才真正的影响着子表达式的匹配行为。如果整个表达式匹配失败,贪婪模式只会影响匹配过程,对匹配结果的影响无从谈起。其实里面水还很深的,如果想要弄清楚具体的非贪婪性重复的使用,那还要查阅更多的资料。
-
选择、分组和引用
都是很字面的意思,选择就是多个正则规则里面选择一个;分组就是将多个小正则规则作为一个小组;引用就是引用前面的某一项正则规则的匹配结果。还是上图表吧
字符 | 含义 | 例子 | 注释 |
---|---|---|---|
| | 选择,可能用于匹配的正则规则是该竖线左边的或右边的 | \d|A | 匹配一个数字或一个大写字母A,因为是从\d和A两个规则中选一个进行匹配,所以不能匹配类似于1A这样的数字组合 |
(...) | 组合,把多项正则规则组合在一起,便于重复字符等对它们的共同作用 | (\dA)+ | \dA匹配的是1A这样的“一个数字一个字母A”的组合,但是后面跟了一个+,说明匹配前一项1或者是更多次,如1A2A这样的组合也是可以被匹配的 |
\n | 引用,通过记录前面的括号分组数(嵌套的也算),便于在后面直接引用 | (\dA(\dB))(\dC)\3 | \3引用的是(\dC)组,所以能通过匹配的字符应该是1A2B3C3C,注意引用的是(\dC)项的匹配结果,如1A2B3C4C是不能匹配成功的 |
(?:...) | 只组合,不被引用记录 | (\dA(\dB))(?:\dE)(\dC)\3 | \3引用的还是(\dC)组,能通过匹配的字符串,形为1A2B3E4C4C |
我觉得表中已经够详细了,不补充了,任性
-
匹配位置
正则表达式可以让你选择匹配的是一段字符串的某些位置,如定位开头用^、定位末尾用$等。我们将这类字符称为锚字符。
锚字符表
字符 | 含义 | 例子 | 注释 |
---|---|---|---|
^ | 匹配字符串的开头 | ^\d | 匹配以数字开头的字符串,例如1abcd是能够被匹配成功的,而abcd就不能 |
$ | 匹配字符串的末尾 | \d$ | 匹配数字结尾的字符串,如abcd1 |
\b | 匹配单词的边界,就是位于字符\w与\w之间的位置 | \b1(\w)+2\b | 匹配的是以1开头以2结尾的单词,例如字符串“1111 aaa 1bbbb2 2222”是能通过匹配的,因为该字符串里面的1bbbb2通过了正则规则 |
还有零宽正向先行断言(?=p)和零宽负向先行断言(?!p),不是很常用,我就不解释了,想要了解的可以自己查阅资料。
-
修饰符
这里要补充一个知识点,前面所讲到的正则规则都是需要放在/ /之间,至于原因,后面在JS的使用举例中会解释。但是本小节所讲的修饰符是放在/ /右边的,作用是为了给前面的全体正则规则作补充。
修饰符
字符 | 含义 | 例子 | 注释 |
---|---|---|---|
i | 执行不区分大小写的比较 | /a/i | 虽然前面定义了要匹配小写的字母a,但是由于后面的i的作用,A也是能够匹配成功的 |
g | 执行全局匹配,即找出一个字符串中所有的匹配项 | /a/g | 如可以匹配字符串"acdcdacdc"中的两个a都是会被匹配的 |
m | 多行匹配 | /^a/m | 如果有一个字符串里面有很多行,它可以匹配每一行前面的a,例如"abc\nbdc",会对两行的开头进行匹配,但是匹配成功一个就好了 |
上面三个修饰符可以根据自己想要的效果进行组合使用。
-
综合举例
在这里我会举一个前端表单中常用的例子,那就是邮箱地址的正则验证。这个栗子不是很大,但是味道应该也还不错的吧...
上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RegExpDemo</title>
</head>
<body>
<input type="text" id="email" placeholder="请您输入邮箱地址">
<input type="submit" id="check" value="验证">
</body>
<script>
var email = document.getElementById("email").value;
var oCheck = document.getElementById("check");
var reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
oCheck.onclick=function( ){
if(email != ""){
if(reg.test(email)){
alert("邮箱合法!");
}else{
alert("邮箱不合法!");
}
}
}
</script>
</html>
这个例子的验证结果不方便截图,所以想看运行结果的朋友,只能自己copy代码运行一下咯
这代码验证的只是邮箱的基本形式,并不能验证邮箱地址是否真实存在。有的人在做匹配的时候,@符号后面的网址用的是固定网址组合,如(sina.cn|qq.com)之类的,但是我觉得这样具有局限性,我们并不能完全将所有的邮箱都举例齐全,例如我学校的邮件系统用的就是@hfut.edu.cn。要是不在组合的选择范围内,那我的邮箱不就不能在该网站上正常使用了么?这不科学啊
现在我就用图,开始一步一步的解析这个邮箱地址的正则,当然,实在是很简单的,例如,“重复字符*表示至少匹配0次”这样的简单概念,我就不一个一个说了,忘了的话,就向上翻看以下吧。
虽然正则表达式看起来很长很麻烦的样子,但是将其拆分来看,还是很容易看懂的。
以上的就是基本的正则使用规则,接下来是介绍如何在js中使用正则
JavaScript中的正则使用
-
RegExp对象
JavaScript中的正则表达式用RegExp对象表示,可以用RegExp( )构造函数创建对象,或者是特殊的直接量//直接创建,如
1 var reg1= new RegExp ("\\d", "g");// 用构造函数创建
2 var reg2 = /\d/g;//用直接量创建
注:用构造函数创建RegExp对象的时候,其构造函数可以接受两个参数,参数1是正则规则/ /之间的部分,参数2是正则的修饰符。而且不论是字符串直接量还是正则表达式,都要使用“\”作为转义字符的前缀。
可以看出第二种方法比较比较方便,所以后续的例子我都会使用方法2创建RegExp对象。
-
RegExp对象的方法
RegExp对象定义了两个用于执行模式匹配操作的方法,分别为exec( )和test( )。
1.exec( )方法的使用
使用该方法在一个字符串中执行匹配搜索,如果它没有找到任何匹配,就会返回null
值,如果匹配成功就会返回一个数组,该数组的index属性包含了发生匹配的位置。通过RegExp对象的lastIndex属性可以知道,exec( )方法的下一次匹配位置在哪里。注意:exec( )方法最好要与修饰符g一起使用,不然浏览器可能会被你弄崩溃的哦,切记切记。至于原因,大家可以自行查阅资料,我怕我说不清楚的话,会误导大家。下面举一个小小的栗子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RegExpDemo1</title>
</head>
<body>
</body>
<script>
var reg = /\da/gi; //用直接量创建一个RegExp对象,并用于匹配一个数字和一个字母a
var text = "1a2A3b4c";
var result = null;
document.write("待匹配字符串是"+text+"<br/>");
while((result = reg.exec(text)) != null){
document.write("匹配到"+result[0]+",位置是"+result.index+",下一次开始匹配的位置是"+reg.lastIndex+";<br/>");
}
</script>
</html>
运行结果为:
exec( )的使用这里我使用两个修饰符g和i,i可以让我们既能匹配a又能匹配A。
2.test( )方法的使用
这方法与exec( )方法类似,但是比它简单。test( )方法会对字符串进行匹配,只要匹配成功了,就返回true,反之,返回false。又上一个小栗子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RegExpDemo2</title>
</head>
<body>
</body>
<script>
var reg = /\da/gi;
var text1 = "1a2A3b4c";
var text2 = "11111";
document.write("待匹配字符串是"+text1+"和"+text2+"<br/>");
document.write(reg.test(text1)+"</br>");
document.write(reg.test(text2));
</script>
</html>
运行结果为:
test( )的使用
可以看出,如果只是想验证字符串时候符合正则规则的话,用test( )方法就可以了。
吐槽一下
写的不是很好,但是在javaScript中的基本正则使用都已经解释清楚了。因为海燕最近一直在考试,所以是断断续续写的,就当是拿来放松心情了。都考了3个星期了,明天是这星期的最后一门,加油啊亲爱的,赶紧滚去复习,明天考完试我就让你看完岛上书店>_<
by haiyan