从零开始学正则(七:终章)

 壹 ❀ 引html

花了差很少半个月的晚上时间,正则入门学习也步入尾声了,固然正则的学习还将继续。不得不说学习成效很是明显,已能看懂大部分正则以及写出不太复杂的正则,好比帮组长写正则验证文件路径正确性,再如进产品页根据页面地址获取产品id:git

let pathname = '/webtoprint/dynamicsize-gamebox-2033986.html';
let productId = pathname.match(/\-(\d+)\./)[1]; //2033986

虽然正则都不难,可是相比以前使用split各类切切切真的要舒服的多,想到这一点就开心。因此若是有缘的你看到这篇做为结束的文章,仍是很是推荐静下心花点闲余时间学习正则。github

那么在最终章,咱们将正则与API结合起来,真正把正则用起来,毕竟学了不用总会忘,忘了再学就巨亏。说在前面,正则学习系列文章均为我阅读 老姚《JavaScript正则迷你书》的读书笔记,文中全部正则图解均使用regulex制做。那么本文开始!web

 贰 ❀ 正则的四种操做数组

咱们知道正则是一种匹配模式,要么匹配字符,要么匹配位置,正则的核心用处就是在于匹配咱们预期的东西。那么拿到了想要的东西能作什么?其实无非就是用于验证,切分,提取以及替换。好比文章开头匹配产品id就是提取咱们想要的东西,再如千位分隔符就是将数字替换成咱们想要的样子,其实也不难理解,咱们来细说这四种操做。函数

1.验证学习

谈到验证首先想到的就是表单验证,使用正则验证用户输入字段是否符合规范,好比验证数字密码长度是否为六位,最经常使用的就是使用test方法:spa

var regex = /^\d{6}$/;
regex.test(123456); //true
regex.test(12345); //false
regex.test(1234567); //false

除了字符的完整比较验证,有时候咱们也须要验证字符中是否包含某个特定字符,这种状况下除了test,咱们能用match,search,exec这三个方法来作,好比验证字符中是否包含 ❀ :3d

可使用 test 方法:code

var regex = /❀/;
regex.test('123❀'); //true
regex.test('a❀b'); //false
regex.test('echo'); //false

使用match方法,此时返回并不是布尔值,而是匹配结果,若要判断有没有只需对比返回值是否等于null便可:

var regex = /❀/;
'123❀'.match(regex); //["❀", index: 3, input: "123❀", groups: undefined]
'a❀b'.match(regex); //["❀", index: 1, input: "a❀b", groups: undefined]
'echo'.match(regex); //null

使用search方法,此时返回第一个符合条件字符的索引,若没找到返回-1,因此判断有没有对比是否等于-1便可:

var regex = /❀/;
'❀123❀'.search(regex); //0
'a❀b'.search(regex); //1
'echo'.search(regex); //-1

使用exec方法,此方法结果与match相似,判断有没有看是否为null便可:

var regex = /❀/;
regex.exec('❀123❀'); //["❀", index: 0, input: "❀123❀", groups: undefined]
regex.exec('a❀b'); //["❀", index: 1, input: "a❀b", groups: undefined]
regex.exec('echo'); //null

固然若是真的是判断有没有某个字符的需求,其实用 indexOf 就能够了,这里也只是列举这些方法的做用。

2.切分

说到切分天然想到字符串切分的split方法,好比:

var str = 'hello echo';
var a = str.split(" ");
console.log(a, str); //["hello", "echo"] "hello echo"

split方法返回一个切割后的数组,它并不会修改原字符串。其实split接受参数除了字符意外,它还能接受一个正则做为切分条件,好比上面的例子咱们也能够写成:

var str = 'hello echo';
var a = str.split(/\s/);
console.log(a, str); //["hello", "echo"] "hello echo"

3.提取

正如文章开头提取产品id的例子同样,正则提取操做很是使用,而提取就依赖于正则分组存储的特性,因此分组记得必定不能使用非捕获型括号,看个简单的例子:

var regex = /(\d{4})\/(\d{2})\/(\d{2})/;
var result = regex.exec('2019/12/28'); //["2019/12/28", "2019", "12", "28", index: 0, input: "2019/12/28", groups: undefined]
console.log(result[1]); //2019
console.log(result[2]); //12
console.log(result[3]); //28
// 或直接经过RegExp对象访问
console.log(RegExp.$1); //2019
console.log(RegExp.$2); //12
console.log(RegExp.$3); //28

4.替换

替换必须依赖字符串replace方法,好比将yyyy/mm/dd修改成yyyy-mm-dd:

var str = 'yyyy/mm/dd';
var result = str.replace(/\//g, '-');
console.log(result, str); //yyyy-mm-dd yyyy/mm/dd

注意replace返回替换后的字符,并不会修改原字符串。

 叁 ❀ 正则相关的API使用注意

整合上文四种正则操做能够发现,正则使用的API一共就六个,其中字符串方法四个,正则方法两个:

字符串方法split:负责字符串切分,可以使用正则做为切分条件,返回切分后的数组,不修改原字符串。

字符串方法search:根据正则查找并返回第一个符合条件的字符索引,注意是第一个,若是没找到返回-1。

字符串方法match:根据正则匹配符合条件的字符,返回一个数组,若是没找到返回null,此方法与exec相似。

字符串方法relpace:根据正则条件进行字符替换,返回替换完成的字符,不会修改源字符串。

正则方法exec:与match相似,返回一个包含符合条件字符,分组匹配字符等信息的数组,没找到返回null。

正则方法test:验证时经常使用,验证字符是否有符合正则条件的字符,返回一个Boolean值,有为true,没有返回false。

在使用这些方法时,仍是有一些须要注意的点,这里咱们作个整合:

1.search与match会将字符参数转为正则

字符串的split,replact,match,search四个方法都接受字符串或者正则做为参数,但在使用时,match与search会将字符串参数转为正则

var str = '2019.12.28';
var result1 = str.search('.'); //0
var result2 = str.match('.'); //["2", index: 0, input: "2019.12.28", groups: undefined]

在上面的例子,咱们本意是匹配第一个小数点的位置,但这两个方法将小数点转为了正则,也就是通配符,很天然第一个数字2就符合条件,因此search返回了2的索引0,match返回了2。

为了不这个问题仍是建议匹配条件直接使用正则,避免没必要要的麻烦,像这样:

var str = '2019.12.28';
var result1 = str.search('\\.'); //4
var result2 = str.match(/\./); //[".", index: 4, input: "2019.12.28", groups: undefined]

固然若是只是查找某个字符有没有,仍是推荐indexOf,不用像上面花里胡哨。

2.match匹配受修饰符g影响

咱们在前面说字符串方法match与正则方法exec很是相似,若成功匹配都是返回一个数组,失败返回null,而数组中包含了第一个符合条件的字符,分组捕获字符等信息:

var str = '2019.12.28';
var result1 = str.match(/\d+/); //["2019", index: 0, input: "2019.12.28", groups: undefined] 
var result2 = /\d+/.exec('2019.12.28'); //["2019", index: 0, input: "2019.12.28", groups: undefined] 

能够看到不加g状况两个方法匹配结果彻底同样,如今咱们加上全局匹配修饰符g再看:

var str = '2019.12.28';
var result1 = str.match(/\d+/g); //["2019", "12", "28"]
var result2 = /\d+/g.exec('2019.12.28'); //["2019", index: 0, input: "2019.12.28", groups: undefined]

match方法的正则添加了修饰符g,返回结果将只包含全部符合条件的字符,再也不包含字index等信息。而exec方法很明显不受g影响。

3.exec使用修饰符g的妙用

上面说match方法使用了g虽然能拿到全部符合条件的字符,但不知道每次出现的索引信息,exec正好解决了这个问题。

当exec方法使用了修饰符g,exec第一次匹配从索引0开始,以后每次匹配都会从上次匹配失败的索引位置(lastIndex)开始,直至匹配一圈后重置索引为0,也就是开始下一轮匹配:

var str = '2019.12.28';
var regexp = /\d+/g
console.log(regexp.exec('2019.12.28'), regexp.lastIndex); // ["2019", index: 0, input: "2019.12.28", groups: undefined] 4
console.log(regexp.exec('2019.12.28'), regexp.lastIndex); // ["12", index: 5, input: "2019.12.28", groups: undefined] 7
console.log(regexp.exec('2019.12.28'), regexp.lastIndex); // ["28", index: 8, input: "2019.12.28", groups: undefined] 10
console.log(regexp.exec('2019.12.28'), regexp.lastIndex); // null 0
console.log(regexp.exec('2019.12.28'), regexp.lastIndex); // ["2019", index: 0, input: "2019.12.28", groups: undefined] 4

能够看到在走完第四次匹配后,字符串被完整匹配了一遍,此时lastIndex又被重置为0,接下来又开始新一轮匹配。

4.test也会受修饰符g影响

前面说exec会受g影响,准确来讲正则的两个方法都受g影响,另外一个方法test也是如此,只要添加了全局修饰符g,正则每次匹配完成都会修改lastIndex,这一点与exec保持一致:

var str = '2019.12.28';
var regexp = /\d+/g
console.log(regexp.test('2019.12.28'), regexp.lastIndex); // true 4
console.log(regexp.test('2019.12.28'), regexp.lastIndex); // true 7
console.log(regexp.test('2019.12.28'), regexp.lastIndex); // true 10
console.log(regexp.test('2019.12.28'), regexp.lastIndex); // false 0
console.log(regexp.test('2019.12.28'), regexp.lastIndex); //true 4

5.验证字符总体要加^和$

这个在前面几篇文章已经有说过,通常咱们验证用户输入表单信息,都是验证用户输入的完整字符是否符合规格,因此要验证总体是否符合,必定得加^和$:

var regexp = /\d{6}/;
console.log(regexp.test('1234567')); // true
console.log(regexp.test('123456')); // true

var regexp = /^\d{6}$/;
console.log(regexp.test('1234567')); // false
console.log(regexp.test('123456')); // true

好比这个例子中咱们要求密码必须是6位数字,若是不加^和$,七位数字也包含了六位数字的状况,因此为true。

6.split你不知道的事

split方法咱们在前面说了它接受一个字符或者一个正则做为切分字符的条件,并将字符按此条件切成一个数组并返回。

其实split方法还能接受第二个参数,用于限定返回数组的长度:

var str = '听风是风 时间跳跃 行星飞行 echo';
console.log(str.split(' ', 2)); //["听风是风", "时间跳跃"]

第二点是,若是咱们使用正则做为切分条件,且正则使用了分组,那么返回的数据将包含分隔符:

var str = '听风是风 时间跳跃 行星飞行 echo';
console.log(str.split(/(\s)/)); //["听风是风", " ", "时间跳跃", " ", "行星飞行", " ", "echo"]

7.强大的replace方法

咱们理解的replace方法第二参数就是自定义字符,最基本的用法:

var str = '听风是风 时间跳跃 行星飞行 echo';
console.log(str.replace(/\s/g,'❀')); //听风是风❀时间跳跃❀行星飞行❀echo

其实正则自身也提供了一部分字符,以下:

属性 描述
$1,$2...$99 匹配第1-99个分组里捕获的文本
$& 匹配到的子串文本
$` 匹配到的子串的左边文本
$' 匹配到的子串的右边文本
$$ 美圆符号

好比将 2019/12/29 替换成 2019-12-28,能够这么作,这里解释了$1,$2含义:

var str = '2019/12/29';
console.log(str.replace(/(\d{4})\/(\d{2})\/(\d{2})/g, '$1-$2-$3')); //2019-12-29

console.log(RegExp.$1); //2019
console.log(RegExp.$2); //12
console.log(RegExp.$3); //29

咱们来经过一个例子来解释$&,以下:

var result = "a,b,c".replace(/\w/g, "$&$&");
console.log(result);//aa,bb,cc

不少人看到这里可能就不理解了,这是怎么替换的?记住一点,replace具备遍历特性,前面正则能匹配到几回,后面的替换就会执行几回。

第一次匹配到了a,因此此时的 $&表示 a,执行替换,a被替换成了 aa。

第二次匹配到了b,此时的$&表示 b,又执行替换,此时b又变成了bb,以此类推,经历过三次替换因而变成了aa,bb,cc。

咱们经过一个例子来解释 $` 和 $':

var result = "2+3=5".replace(/=/, "$`----$'");
console.log(result); //2+32+3----55

整个匹配下来只有一个 = ,因此$`表示 = 左边的内容,也就是2+3,对应的 $'表示 = 右边的内容,也就是5。别忘了replace是将匹配到的内容替换掉,因此 = 被替换成了 2+3----5。

说到这确定有同窗问了,要死我有多个 = 符号你咋替换,别忘了replace是会遍历的,它会循环起来一步步替换,看个例子:

var result = "2=3=5".replace(/=/g, "$`$'");
console.log(result); //223=532=355

因为加了修饰符g,因此这里会匹配量词,先说第一次,=左边是2,右边是3=5,组合起来就是 23=5,替换到=上去以后就是223=53=5。

匹配到了第二个 = ,注意,此时 = 左右不是以修改的字符做为标准,而是继续以修改前的原字符做为切割标准,因此第二个 = 左边是2=3,右边是5,组合起来就是2=35,替换到 223=53=5 第二个 = 上,因而就变成了 223=532=355。

不难理解,可是懒得理解....实际开发中使用$1此类字符串较多,其它字符就随缘了。但其实说到这里,咱们仍是强调一点,replace会遍历替换。

replace方法第二个参数还能够是一个回调函数,这里就能够验证咱们说的replace会遍历的说法:

"1234 2345 3456".replace(/(\d)\d{2}(\d)/g, function (match, $1, $2, index, input) {
    console.log([match, $1, $2, index, input]);
});
// ["1234", "1", "4", 0, "1234 2345 3456"]
// ["2345", "2", "5", 5, "1234 2345 3456"]
// ["3456", "3", "6", 10, "1234 2345 3456"]

8.正则构造函数

与通常对象建立可使用对象字面量,构造函数建立对象同样,正则也能使用构造函数建立。请记住一点,能使用字面量的状况必定使用字面量。有一种特殊状况必须使用构造函数建立,那就是正则内容是一个变量,好比:

function regexp(param) {
    var regex = new RegExp(param, 'g');
    console.log(regex.test('听风是风'));//true
    console.log(regex.test('时间跳跃 听风是风'));//true
    console.log(regex.test('时间跳跃'));//false
};
regexp('听风是风');

固然就算不是变量状况,咱们也能用构造函数建立固定字符的正则,但本来有\的字符前你得多加一个\,因此你会发现这样的正则特别难读,像这样:

var regex = new RegExp('\\d+\\.\\d+', 'g');
console.log(regex.test('3.14')); //true
console.log(regex.test('.3.14')); //false

//等同于
var regex = /\d+\.\d+/;

这个正则其实只是用来匹配浮点数,但\d和为了匹配小数点使用了转义符的\d前面都有\,因此通通再得加一个\。因此说嘛,能不用构造函数记得必定不要用。

9.正则source属性

使用构造函数建立正则的另外一个问题就是,你不知道这是否是你想要的正则,对于这一点,咱们能够经过source属性查看:

var regex = new RegExp('\\d+\\.\\d+', 'g');
console.log(regex.source) //\d+\.\d+

10.构造函数属性

在前面聊$1,$&时,我想你们必定有个问题,难道我每次都要根据替换结果来反推这些字符的意思吗?有没有什么办法直接查看呢,实际上是有的:

静态属性 描述 简写方式
 RegExp.input  最近一次目标字符串  RegExp["$_"]
 RegExp.lastMatch  最近一次匹配的文本  RegExp["$&"]
 RegExp.lastParen  最近一次捕获的文本  RegExp["$+"]
 RegExp.leftContext  目标字符串中lastMatch以前的文本  RegExp["$`"]
 RegExp.rightContext  目标字符串中lastMatch以后的文本  RegExp["$'"]

经过静态属性或简写方式,咱们能够直接查看这些字符到底匹配到了什么东西:

var regex = /\w(=)/g;
var string = 'a=b=c';
string.match(regex);
console.log(RegExp.input);
console.log(RegExp["$_"]);
//a=b=c
console.log(RegExp.lastMatch);
console.log(RegExp["$&"]);
// b=
console.log(RegExp.lastParen);
console.log(RegExp["$+"]);
// =
console.log(RegExp.leftContext);
console.log(RegExp["$`"]);
// a=
console.log(RegExp.rightContext);
console.log(RegExp["$'"]);
// c

 肆 ❀ 总

我读完了这本正则表示迷你书,很开心。而后如今断网了,博客没法提交保存,只能用USB连接电脑苟延残喘写个结尾提交了。

无论怎么说,我一路学过来也顺利学完,仍是很是推荐大学花点时间好好学习正则,由于学会了以后在工做中每解决一个正则问题,那种史无前例的快感真是爽到爆炸!!!

好啦,半个月的学习顺利结束,也但愿你能爱上正则,一块儿努力吧,有缘看到此文但陌生的你。

相关文章
相关标签/搜索