一、正则表达式简介
1.定义:正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。
2.正则表达式的特点是:
(1)灵活性、逻辑性和功能性非常强;
(2)可以迅速地用极简单的方式达到字符串的复杂控制。
(3) 对于刚接触的人来说,比较晦涩难懂。
3.应用:由于正则表达式主要应用对象是文本,因此它在各种文本编辑器场合都有应用,小到著名编辑器EditPlus,大到Microsoft Word、Visual Studio等大型编辑器,都可以使用正则表达式来处理文本内容。
二、正则表达式的创建
1.使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:
var re = /ab+c/;
脚本加载后,正则表达式字面量就会被编译。当正则表达式保持不变时,使用此方法可获得更好的性能。
或者调用RegExp
对象的构造函数,如下所示:
var re = new RegExp("ab+c");
在脚本运行过程中,用构造函数创建的正则表达式会被编译。如果正则表达式将会改变,或者它将会从用户输入等来源中动态地产生,就需要使用构造函数来创建正则表达式。
2.编写一个正则表达式:
(1)使用一个简单模式创建
简单模式是由你想直接找到的字符构成。比如,/abc/
这个模式就能且仅能匹配 "abc" 字符按照顺序同时出现的情况。例如在 "Hi, do you know your abc's?" 和 "The latest airplane designs evolved from slabcraft." 中会匹配成功。在上述两个例子中,匹配的子字符串是 "abc"。但是在 "Grab crab" 中会匹配失败,因为它虽然包含子字符串 "ab c",但并不是准确的 "abc"。
(2)使用特殊符号创建
下面的页面与表格列出了一个正则表达式中可以利用的特殊字符的完整列表和描述。
表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。
区分不同类型的字符,例如区分字母和数字。
表示表达式字符的分组和范围。
表示匹配的字符或表达式的数量。
Unicode 属性转义(Unicode Property Escapes)
基于 unicode 字符属性区分字符。例如大写和小写字母、数学符号和标点。
字符 | 含义 |
---|---|
\ | 依照下列规则匹配: 在非特殊字符之前的反斜杠表示下一个字符是特殊字符,不能按照字面理解。例如,前面没有 "\" 的 "b" 通常匹配小写字母 "b",即字符会被作为字面理解,无论它出现在哪里。但如果前面加了 "\",它将不再匹配任何字符,而是表示一个字符边界。 在特殊字符之前的反斜杠表示下一个字符不是特殊字符,应该按照字面理解。详情请参阅下文中的 "转义(Escaping)" 部分。 如果你想将字符串传递给 RegExp 构造函数,不要忘记在字符串字面量中反斜杠是转义字符。所以为了在模式中添加一个反斜杠,你需要在字符串字面量中转义它。 |
^ | 匹配输入的开始。如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。 例如, 当 ' |
$ | 匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。 例如, |
* | 匹配前一个表达式 0 次或多次。等价于 例如, |
+ | 匹配前面一个表达式 1 次或者多次。等价于 例如, |
? | 匹配前面一个表达式 0 次或者 1 次。等价于 例如, 如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。例如,对 "123abc" 使用 还用于先行断言中,如本表的 |
. | (小数点)默认匹配除换行符之外的任何单个字符。 例如, 如果 |
(x) | 像下面的例子展示的那样,它会匹配 'x' 并且记住匹配项。其中括号被称为捕获括号。 模式 |
(?:x) | 匹配 'x' 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 |
x(?=y) | 匹配'x'仅仅当'x'后面跟着'y'.这种叫做先行断言。 例如,/Jack(?=Sprat)/会匹配到'Jack'仅当它后面跟着'Sprat'。/Jack(?=Sprat|Frost)/匹配‘Jack’仅当它后面跟着'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。 |
(?<=y) x | 匹配'x'仅当'x'前面是'y'.这种叫做后行断言。 例如,/(?<=Jack)Sprat/会匹配到' Sprat '仅仅当它前面是' Jack '。/(?<=Jack|Tom)Sprat/匹配‘ Sprat ’仅仅当它前面是'Jack'或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。 |
x(?!y) | 仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找。 例如,仅仅当这个数字后面没有跟小数点的时候,/\d+(?!\.)/ 匹配一个数字。正则表达式/\d+(?!\.)/.exec("3.141")匹配‘141’而不是‘3.141’ |
(?<!y)x | 仅仅当'x'前面不是'y'时匹配'x',这被称为反向否定查找。 例如, 仅仅当这个数字前面没有负号的时候, |
x|y | 匹配‘x’或者‘y’。 例如,/green|red/匹配“green apple”中的‘green’和“red apple”中的‘red’ |
{n} | n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。 比如, /a{2}/ 不会匹配“candy”中的'a',但是会匹配“caandy”中所有的 a,以及“caaandy”中的前两个'a'。 |
{n,} | n是一个正整数,匹配前一个字符至少出现了n次。 例如, /a{2,}/ 匹配 "aa", "aaaa" 和 "aaaaa" 但是不匹配 "a"。 |
{n,m} | n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。 例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。 |
[xyz] | 一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。 例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。/[a-z.]+/ 和/[\w.]+/与字符串“test.i.ng”匹配。 |
[^xyz] | 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。 例如,[^abc] 和 [^a-c] 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。 |
[\b] | 匹配一个退格(U+0008)。(不要和\b混淆了。) |
\b | 匹配一个词的边界。一个词的边界就是一个词不被另外一个“字”字符跟随的位置或者前面跟其他“字”字符的位置,例如在字母和空格之间。注意,匹配中不包括匹配的字边界。换句话说,一个匹配的词的边界的内容的长度是0。(不要和[\b]混淆了) 使用"moon"举例: 注意: JavaScript的正则表达式引擎将特定的字符集定义为“字”字符。不在该集合中的任何字符都被认为是一个断词。这组字符相当有限:它只包括大写和小写的罗马字母,十进制数字和下划线字符。不幸的是,重要的字符,例如“é”或“ü”,被视为断词。 |
\B | 匹配一个非单词边界。匹配如下几种情况:
例如,/\B../匹配"noonday"中的'oo', 而/y\B../匹配"possibly yesterday"中的’yes‘ |
\cX | 当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符。 例如, |
\d | 匹配一个数字 例如, |
\D | 匹配一个非数字字符 例如, |
\f | 匹配一个换页符 (U+000C)。 |
\n | 匹配一个换行符 (U+000A)。 |
\r | 匹配一个回车符 (U+000D)。 |
\s | 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。 例如, 经测试,\s不匹配"\u180e",在当前版本Chrome(v80.0.3987.122)和Firefox(76.0.1)控制台输入/\s/.test("\u180e")均返回false。 |
\S | 匹配一个非空白字符。等价于 例如, |
\t | 匹配一个水平制表符 (U+0009)。 |
\v | 匹配一个垂直制表符 (U+000B)。 |
\w | 匹配一个单字字符(字母、数字或者下划线)。等价于 例如, |
\W | 匹配一个非单字字符。等价于 例如, |
\n | 在正则表达式中,它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数)。 比如 |
\0 | 匹配 NULL(U+0000)字符, 不要在这后面跟其它小数,因为 \0<digits> 是一个八进制转义序列。 |
\xhh | 匹配一个两位十六进制数(\x00-\xFF)表示的字符。 |
\uhhhh | 匹配一个四位十六进制数表示的 UTF-16 代码单元。 |
| (仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符。 |
3.使用插入语创建
任何正则表达式的插入语都会使这部分匹配的副字符串被记忆。一旦被记忆,这个副字符串就可以被调用于其它用途,如同 使用括号的子字符串匹配之中所述。
比如, /Chapter (\d+)\.\d*/
解释了额外转义的和特殊的字符,并说明了这部分pattern应该被记忆。它精确地匹配后面跟着一个以上数字字符的字符 'Chapter ' (\d
意为任何数字字符,+ 意为1次以上
),跟着一个小数点(在这个字符中本身也是一个特殊字符;小数点前的 \ 意味着这个pattern必须寻找字面字符 '.'),跟着任何数字字符0次以上。 (\d
意为数字字符, *
意为0次以上)。另外,插入语也用来记忆第一个匹配的数字字符。
此模式可以匹配字符串"Open Chapter 4.3, paragraph 6",并且'4'将会被记住。此模式并不能匹配"Chapter 3 and 4",因为在这个字符串中'3'的后面没有点号'.'。
括号中的"?:",这种模式匹配的子字符串将不会被记住。比如,(?:\d+)匹配一次或多次数字字符,但是不能记住匹配的字符。
三、正则表达式的使用
方法 | 描述 |
---|---|
exec | 一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回 null)。 |
test | 一个在字符串中测试是否匹配的RegExp方法,它返回 true 或 false。 |
match | 一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null。 |
matchAll | 一个在字符串中执行查找所有匹配的String方法,它返回一个迭代器(iterator)。 |
search | 一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。 |
replace | 一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。 |
split | 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法。 |
在接下来的例子中,脚本将使用exec方法在一个字符串中查找一个匹配。
var myRe = /d(b+)d/g;
var myArray = myRe.exec("cdbbdbsbz");
如果你不需要访问正则表达式的属性,这个脚本通过另一个方法来创建myArray:
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
// 和 "cdbbdbsbz".match(/d(b+)d/g); 相似。
// 但是 "cdbbdbsbz".match(/d(b+)d/g) 输出数组 [ "dbbd" ],
// 而 /d(b+)d/g.exec('cdbbdbsbz') 输出数组 [ "dbbd", "bb", index: 1, input: "cdbbdbsbz" ].
如果你想通过一个字符串构建正则表达式,那么这个脚本还有另一种方法:
var myRe = new RegExp("d(b+)d", "g");
var myArray = myRe.exec("cdbbdbsbz");
通过这些脚本,匹配成功后将返回一个数组并且更新正则表达式的属性,如下表所示。
对象 | 属性或索引 | 描述 | 在例子中对应的值 |
---|---|---|---|
myArray | 匹配到的字符串和所有被记住的子字符串。 | ["dbbd", "bb"] | |
index | 在输入的字符串中匹配到的以0开始的索引值。 | 1 | |
input | 初始字符串。 | "cdbbdbsbz" | |
[0] | 最近一个匹配到的字符串。 | "dbbd" | |
myRe | lastIndex | 开始下一个匹配的起始索引值。(这个属性只有在使用g参数时可用在 通过参数进行高级搜索 一节有详细的描述.) | 5 |
source | 模式字面文本。在正则表达式创建时更新,不执行。 | "d(b+)d" |
如这个例子中的第二种形式所示,你可以使用对象初始器创建一个正则表达式实例,但不分配给变量。如果你这样做,那么,每一次使用时都会创建一个新的正则表达式实例。因此,如果你不把正则表达式实例分配给一个变量,你以后将不能访问这个正则表达式实例的属性。例如,假如你有如下脚本:
var myRe = /d(b+)d/g;
var myArray = myRe.exec("cdbbdbsbz");
console.log("The value of lastIndex is " + myRe.lastIndex);
Copy to Clipboard
这个脚本输出如下:
The value of lastIndex is 5
然而,如果你有如下脚本:
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex);
Copy to Clipboard
它显示为:
The value of lastIndex is 0
当发生/d(b+)d/g使用两个不同状态的正则表达式对象,lastIndex属性会得到不同的值。如果你需要访问一个正则表达式的属性,则需要创建一个对象初始化生成器,你应该首先把它赋值给一个变量。
正则表达式表单验证实例:
html代码:
<form name="myform" action="" onsubmit="return fun1()">
<div align="center">
<table border="1" width="60%" >
<tr>
<td colspan=2 align=center><h3>学生信息管理</h3></td>
</tr>
<tr>
<td height="39" width="463" bgcolor="#006699">
<font color="#FFFF00">学生编号:</font><input type="text" maxlength=10 id="sno" value="12345678">(8位数字)
</td>
<td height="39" width="463" bgcolor="#006699">
<font color="#FFFF00">学生名字:</font><input type="text" maxlength=10 id="username" value="刘训">(中文)
</td>
</tr>
<tr>
<td height="39" width="463" bgcolor="#006699">
<font color="#FFFF00">邮箱地址:</font><input type="text" maxlength=10 id="email" value="1056125478@qq.com">
</td>
<td height="39" width="463" bgcolor="#006699">
<font color="#FFFF00">电话号码:</font><input type="text" maxlength=11 id="tel" value="15574074751">
</td>
</tr>
<tr>
<td height="53" width="985" bgcolor="#006699" colspan="2" align=center>
<input type="submit" value="使用submit按钮提交表单">
</td>
</tr>
</table>
JavaScript代码:
/*是否带有小数*/
function isDecimal(strValue ) {
var objRegExp= /^\d+\.\d+$/;
return objRegExp.test(strValue);
}
/*校验是否中文名称组成 */
function ischina(str) {
var reg=/^[\u4E00-\u9FA5]{2,4}$/; /*定义验证表达式*/
return reg.test(str); /*进行验证*/
}
/*校验是否全由8位数字组成 */
function isStudentNo(str) {
var reg=/^[0-9]{8}$/; /*定义验证表达式*/
return reg.test(str); /*进行验证*/
}
/*校验电话码格式 */
function isTelCode(str) {
var reg= /^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/;
return reg.test(str);
}
/*校验邮件地址是否合法 */
function IsEmail(str) {
var reg=/^\w+@[a-zA-Z0-9]{2,10}(?:\.[a-z]{2,4}){1,3}$/;
return reg.test(str);
}
function fun1(){
if(!isStudentNo(document.getElementById("sno").value)){
alert("学生编号是8位数字");
document.getElementById("sno").focus();
return false;
}
if(!ischina(document.getElementById("username").value)){
alert("学生姓名必须填写中文");
document.getElementById("username").focus();
return false;
}
if(!IsEmail(document.getElementById("email").value)){
alert("邮箱地址错误");
document.getElementById("email").focus();
return false;
}
if(!isTelCode(document.getElementById("tel").value)){
alert("电话号码不对");
document.getElementById("tel").focus();
return false;
}
/*运行到这里说明验证通过返回true submit提交按钮起作用提交表单*/
alert("提交成功")
return false; // 这边设置禁止提交,实际项目需要改为 true
}
效果:
注:本文借鉴于菜鸟教程,百度百科,以及MDN Web Docs,如有侵权,无意冒犯,请联系本文作者删除处理。