本文内容主要出处为《JavaScript权威指南》(第六版),笔者只是在搬砖的同时整理思路,有误望及时指出,感谢!javascript
定义正则表达式
对于正则表达式的概念咱们就很少费口舌了...
在JavaScript中使用正则表达式进行模式匹配离不开RegExp
对象,建立正则对象有两种方式
1.正则表达式直接量(包含在一对/
之间的字符)html
var reg = /java/;
reg.test('java'); // true复制代码
2.new RegExp()
java
var reg = new RegExp('java');
reg.test('java'); // true复制代码
JavaScript也赋予了String
对象进行模式匹配的方法,可是使用这些方法的时候一样离不开RegExp
例如:c++
var str = 'java';
str.match(/java/); // /java/为正则直接量复制代码
String
与 RegExp
如何进行正则匹配,有哪些方法,会在下面两节讲解,这一节(定义正则表达式),主要讲述如何定义正则表达式(本节会用到RegExp
的 test
和 exec
方法,如若不了解,能够与最后一节结合来理解)正则表达式
直接字符量表示字符在正则表达式中的表达形式。特殊字符需\
转义数组
字母、数字 -> 自身
\o -> NUL字符(\u0000)
\t -> 制表符(\u0009)
\n -> 换行符(\u000A)
\v -> 垂直制表符(\u000B)
\f -> 换页符(\u000C)
\r -> 回车符(\u000D)
...复制代码
将字符量放入 []
中就成了字符类,字符类匹配它包含的任意一个字符函数
[abc] // 表示a 或者b 或者c
[^abc] // ^在这里表示取反,除了a、b、c以外的全部字符
[a-z] //-表示链接,从a到z的任意字符复制代码
由上面咱们能够知道,[0-9]
表示任意数字,像这种经常使用的字符类,JavaScript给他们制订了本身的特殊转义字符。ui
. // 除换行符与其余Unicode行终止符之外的任意字符
\w // 等价于[a-zA-Z0-9_],大小写字母、数字、下划线63字符中任意一个
\W // 等价于[^a-zA-Z0-9_]
\s // 任何Unicode空白符
\S // 任何Unicode非空白符
\d // 等价于[0-9]
\D // 等价于[^0-9]
[\b] // \b放入[]中标识退格直接量复制代码
描述相同字符,屡次出现spa
{n, m} // 最少重复n次,最多重复m次
{n, } // 至少重复n次
{n} //重复n次
? // 等价于 {0, 1}
+ // 等价于 {1,}
* // 等价于 {0,}复制代码
例如:3d
var reg = new RegExp('a{2,}');
var str = 'aaa';
var str2 = 'a';
reg.test(str); // true
reg.test(str2); // false复制代码
在这里会多出一个概念:非贪婪重复
在上述例子中,reg.test(str) === true
咱们用reg.exec(str)
获取匹配结果会发现 结果为'aaa'
若是咱们选择使用非贪婪重复
var reg = new RegExp('a{2,}?');
var str = 'aaa';
reg.exec(str);复制代码
这时候结果为 'aa'
,实现非贪婪重复很简单,在重复后面添加?便可,这时候,正则表达式会尽量少的去匹配重复。
{n, m} -> {n, m}?
{n, } -> {n,}?
{n} -> {n}?
? -> ??
+ -> +?
* -> *?复制代码
用 |
能够分割用于选择的字符,优先级从左向右
ab|cd|ef // 表示 ab 或者 cd 或者 ef复制代码
()
在包裹子表达式同时将其定义为子模式
咱们能够经过 \index
这种写法在同一个正则表达式中调用子模式, index
表示子模式的索引,从1开始。
var reg1 = /(java)script and \1/;
var reg2 = /javascript and java/;
// reg1 与 reg2 是两个基本等价的正则直接量
var str = 'javascript and java';
reg1.test(str); // true
reg2.test(str); // true复制代码
子模式还有助于咱们抽取子表达式匹配结果
把上述例子改成用exec
方法而且打印
var reg1 = /(java)script and \1/;
var reg2 = /javascript and java/;
var str = 'javascript and java';
console.log(reg1.exec(str));
console.log(reg2.exec(str));复制代码
输出结果为:
index
的索引会从1开始,由于0是完整的正则匹配结果。
固然,JavaScript容许咱们在使用子表达式的时候不生成子模式
使用(?: )
来包裹子表达式
var reg = /(?:java)script and java/;复制代码
此时咱们没法经过\1
找到其子模式,也没法获取其子模式的匹配结果。
^ // 字符串开始位置(在字符类中表示取反)
$ // 字符串的结束位置
\b // 单词边界,也就是\w与\W的边界
(?=p) // 要求字符串与p匹配,可是结果集并不包含匹配p的字符
(?!p) // 要求字符串不与p匹配复制代码
^ 与 $
/^javascript/ // 字符串以javascript开始
/javascript$/ // 字符串以javascript结束复制代码
\b
var reg = /\bjava\b/;
var str1 = 'java';
var str2 ='javascript';
var str3 = 'java c++';
var str4 = 'html java c++';
reg.test(str1); // true
reg.test(str2); // false
reg.test(str3); // true
reg.test(str4); // true
在这里 \b 匹配非\w字符,包括字符串起始与结束。
\B与之相反,匹配非单词边界处复制代码
(?=)
var reg = /java(?=script)/;
var str = 'java';
var str1 = 'javascript';
reg.exec(str); // 匹配失败 , 由于不包含script
reg.exec(str1); // 此时匹配成公,可是匹配结果并不包含script复制代码
输出结果为:
var reg = /java(?!script)/;
var str = 'javaee';
var str1 = 'javascript';
reg.exec(str); // 匹配成功,匹配结果为java
reg.exec(str1); // 匹配失败,由于包含script复制代码
i // 不区分大小写
m // 匹配多行(使用^ $指定起止时候能通融\n换行)
g // 匹配成功第一处,并不会继续中止,会继续寻找全部匹配复制代码
经过直接量建立正则对象添加修饰符: /java/gim
(使用多个修饰词直接并列)
经过构造函数建立正则对象添加修饰符: new RegExp(reg , 'gim');
经过String的模式匹配
String对象提供四种方法用于正则匹配。
str.search(reg)
匹配成功返回起始位置,失败返回-1
,在search
方法中修饰词g
不生效
var str = 'hello java';
str.search(/java/); // 6
str.search(/^java/); // -1复制代码
str.match(reg)
匹配失败返回null
,匹配成功返回的是一个由匹配结果组成的数组。若是该正则 表达式设置了修饰符g
,则该方法返回的数组包含字符串中的全部匹配结果。
var str = 'hello java and javascript';
str.match(/java/);
str.match(/java/g);复制代码
输出结果为:
两种调用方式,第二个参数不一样
str.replace(reg , replaceStr)
var str = 'javaee javaee';
// str1 = 'javascript javaee'
var str1 = str.replace(/e{2}/ , 'script');
// str2 = 'javascript javascript' 修饰符g表示全局替换
var str2 = str.replace(/e{2}/g , 'script');
// 补充知识点:str 依然是 javaee ,至于缘由,简单说就是字符串直接量不可改变,字符串全部的有关于值的改变的方法都是return新值。复制代码
第二个参数replaceStr,用于替换的字符串有一些特殊的写法
var reg = /"([^"]*)"/g; // 匹配 "" 间的内容,且内容不包含"
var str = '"java","c++" and "html"';
var str1 = str.replace(reg , '“$1”');
console.log(str1) // “java”,“c++” and “html”复制代码
此时,$1
表示子模式([^"]*)
匹配的结果集, 与咱们上一节定义正则表达式中的调用本身的子模式\1
相仿。
一样,在此处$
还有其余几种用法
$index // 就是上述例子中的$1
$& // 表示原字符串 -> "java","c++" and "html"
$` // 匹配字符串的左侧值,在上述例子中匹配成功三次,分别为: 空值 、 "java", 、"java","c++" and $' // 匹配字符串的右侧值,在上述例子中匹配成功三次,分别为: ,"c++" and "html" 、 and "html" 、空值 $$ // 字符常量$复制代码
str.replace(reg , function)
var reg = /"([^"]*)"/g; // 匹配 "" 间的内容,且内容不包含"
var str = '"java","c++" and "html"';
var str1 = str.replace(reg , function (...arr) {
console.log(arr)
});复制代码
输出结果为:
匹配成功了三次,因此输出了三次arr
数组,这个数组里面的元素分别为:0
: 匹配结果...
: 若存在子模式,这里为子模式匹配结果last - 1
: 索引位置last
: 原字符串
咱们能够根据本身想要的结果,动态替换内容,经过return
将结果替换到新的字符串中。
var reg = /"([^"]*)"/g; // 匹配 "" 间的内容,且内容不包含"
var str = '"java","c++" and "html"';
var str1 = str.replace(reg , function (...arr) {
return `“${arr[1]}”`
});
console.log(str1) // “java”,“c++” and “html”复制代码
str.split(分隔符)
str.split(reg)
var str = 'a,b-c,e,f-g';
var arr = str.split(/[,-]/);
console.log(arr) // ['a','b','c','d','e','f','g']复制代码
经过RegExp的模式匹配
var reg = new RegExp('\\w'); // 经过正则表达式字符串
var reg1 = new RegExp(/\w/); // 经过正则表达式直接量
var reg2 = new RegExp(reg , 'gim'); // 第二个参数为修饰符复制代码
source
: String
正则表达式文本值global
: Boolean
是否携带全局修饰符g
ignoreCase
:Boolean
是否携带忽略大小写修饰符i
multiline
:Boolean
是否携带匹配多行修饰符m
lastIndex
: Number
若是global === true
, 那么这个参数记录每次匹配后的索引位置,下面的test
和exec
方法会用到reg.exec(str)
null
,匹配成功,返回匹配结果,每次执行仅返回一个匹配结果,若global === true
,每次匹配成功后,会把lastIndex
属性设置为紧挨着 匹配子串的字符位置。再次调用此方法,会从当前位置开始匹配(当咱们使用同一个RegExp
匹配新的字符串的时候,最好把lastIndex
属性设置为0)var reg = new RegExp('java' , 'g');
var str = 'javascript java javaee';
var result = reg.exec(str);
while (result) {
console.log(result)
console.log(`lastIndex = ${reg.lastIndex}`)
result = reg.exec(str);
}复制代码
输出结果为:当咱们经过正则表达式直接量来调用进行正则运算的时候,并不会出现这种状况,那是由于在ES5中,每次经过直接量进行正则运算,JavaScript都会生成新的RegExp
对象。
reg.test(str)
test
方法与exec
基本等价,不一样的是他们的返回值,test比较简单粗暴,当exec
返回null
时候,它返回false
,其余状况返回true