壹 ❀ 引

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

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

虽然正则都不难,但是相比之前使用split各种切切切真的要舒服的多,想到这一点就开心。所以如果有缘的你看到这篇作为结束的文章,还是非常推荐静下心花点闲余时间学习正则。

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

 贰 ❀ 正则的四种操作

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

1.验证

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

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

除了字符的完整比较验证,有时候我们也需要验证字符中是否包含某个特定字符,这种情况下除了test,我们能用match,search,exec这三个方法来做,比如验证字符中是否包含 ❀ :

可以使用 test 方法:

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+/g;

这个正则其实只是用来匹配浮点数,但\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链接电脑苟延残喘写个结尾提交了。

不管怎么说,我一路学过来也顺利学完,还是非常推荐大学花点时间好好学习正则,因为学会了之后在工作中每解决一个正则问题,那种前所未有的快感真是爽到爆炸!!!

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

从零开始学正则(七:终章),详解常用正则API与你可能不知道的正则坑的更多相关文章

  1. (转载)一篇文章详解python的字符编码问题

    一篇文章详解python的字符编码问题   一:什么是编码 将明文转换为计算机可以识别的编码文本称为"编码".反之从计算机可识别的编码文本转回为明文为"解码". ...

  2. ISO七层模型详解

    ISO七层模型详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在我刚刚接触运维这个行业的时候,去面试时总是会做一些面试题,笔试题就是看一个运维工程师的专业技能的掌握情况,这个很 ...

  3. UWP入门(七)--SplitView详解与页面跳转

    原文:UWP入门(七)--SplitView详解与页面跳转 官方文档,逼着自己用英文看,UWP开发离不开官方文档 1. SplitView 拆分视图控件 拆分视图控件具有一个可展开/可折叠的窗格和一个 ...

  4. String 字符串详解 / 常用API

    String 详解 / 常用API 简介 String 是不可改变的字符串序列.String 为字符串常量 StringBuilder 与StringBuffer 均为可改变的字符串序列.为字符串变量 ...

  5. 跟我一起学STL(2)——vector容器详解

    一.引言 在上一个专题中,我们介绍了STL中的六大组件,其中容器组件是大多数人经常使用的,因为STL容器是把运用最广的数据结构实现出来,所以我们写应用程序时运用的比较多.然而容器又可以序列式容器和关联 ...

  6. iOS开发——网络编程Swift篇&(七)NSURLSession详解

    NSURLSession详解 // MARK: - /* 使用NSURLSessionDataTask加载数据 */ func sessionLoadData() { //创建NSURL对象 var ...

  7. 大数据入门第七天——MapReduce详解(一)入门与简单示例

    一.概述 1.map-reduce是什么 Hadoop MapReduce is a software framework for easily writing applications which ...

  8. 【小白学PyTorch】11 MobileNet详解及PyTorch实现

    文章来自微信公众号[机器学习炼丹术].我是炼丹兄,欢迎加我微信好友交流学习:cyx645016617. @ 目录 1 背景 2 深度可分离卷积 2.2 一般卷积计算量 2.2 深度可分离卷积计算量 2 ...

  9. Solr系列三:solr索引详解(Schema介绍、字段定义详解、Schema API 介绍)

    一.Schema介绍 1. Schema 是什么? Schema:模式,是集合/内核中字段的定义,让solr知道集合/内核包含哪些字段.字段的数据类型.字段该索引存储. 2. Schema 的定义方式 ...

  10. 配置文件详解和核心api讲解

    一.配置文件详解 1.映射文件详解 1.映射配置文件的位置和名称没有限制. -建议:位置:和实体类放在统一目录下.  名称:实体类名称.hbm.xml.    2.在映射配置文件中,标签内的name属 ...

随机推荐

  1. SV 自定义数据类型

    概述 自定义类型 枚举类型 定义枚举值 自定义枚举类型 枚举类型之间进行赋值是可以的 枚举类型可以赋值给整型,整型不能直接赋值给枚举类型 枚举类型 + 1 ==> 会进行隐式的转换,枚举类型转换 ...

  2. 如何让Dec-C++支持C++11

    1.问题 Dev-C++默认设置中是不支持C++11版本特性的,如Lambda表达式,nullptr等均不提供支持 2.解决 设置编译选项 编译时加上命令-std==c++11即可

  3. 第二届福州大学至诚学院网络安全大赛G0DCTF Misc WP

    MISC baby_misc 1.题目信息 key文件夹: 还有一张图片 2.解题方法 观察key文件夹里的每个文件信息,发现并无什么有用的,甚至有的为空... 看到文件名称的数字而且还给了图片,可以 ...

  4. Go-GC

  5. [转帖]Google SRE 薪水,看看同样作为 SRE 的你相差多少

    https://zhuanlan.zhihu.com/p/566098252 SRE 是确保所有生产环境(Infra/Server/DBS 等)一直正常运行的人.每个网络科技公司基本都有这个部门.但是 ...

  6. [转帖]PD 配置文件描述

    https://docs.pingcap.com/zh/tidb/stable/pd-configuration-file PD 配置文件比命令行参数支持更多的选项.你可以在 conf/config. ...

  7. [转帖]Nginx惊群效应引起的系统高负载

    https://zhuanlan.zhihu.com/p/401910162 原创:蒋院波 导语:本文从进程状态,进程启动方式,网络io多路复用纬度等方面知识,分享解决系统高负载低利用率的案例 前言: ...

  8. [转帖]无需 zookeeper 安装 kafka 集群 (kakfa3.0 版本)

    https://xie.infoq.cn/article/7769ef4576a165f7bdf142aa3 一.kafka 集群实例角色规划 在 kafka3.0 中已经可以将 zookeeper ...

  9. 【转帖】Java Full GC (Ergonomics) 的排查

    文章目录 1. Full GC (Ergonomics) 1.1 Java 进程一直进行 Full GC 1.2 Full GC 的原因 1.3 检查堆占用 2. 代码检查 3. 解决方式 1. Fu ...

  10. [转帖]SQL标准

    SQL 的标准 1986 年 10 月,美国国家标准协会 ANSI 采用 SQL 作为关系数据库管理系统的标准语言,并命名为 ANSI X3. 135-1986,后来国际标准化组织(ISO)也采纳 S ...