共计 5594 个字符,预计需要花费 14 分钟才能阅读完成。
正则表达式作为前端学习的一个知识点,是每个合格的前端开发都应该掌握它的用法。正则表达式的学习确实不难,语法和应用也非常简单,能够快速入门,很轻松的就能写出简单的表达式来对字符串执行某些操作。网上也有标题党说一杯咖啡的时间就能学会。能学会吗?能!但要真正的掌握却不易,就好比篮球运动,40 分钟的一节课,就能学会基本的规则和投球方法,但要做到非常优秀,就需要长时间的练习,学习正则表达式也一样,其实,学习任何知识和技能都是如此,唯有长时间的练习,尽量避免少犯错误,才能达到专业;废话说了一箩筐,下面进入正题;
在实际工作当中,正则表达式应用的场景有:
-
表单验证
- 验证邮箱
- 验证电话
- 是否为空
- etc
- 替换字符串
- 检索字符串
- 开发工具当中的查找和替换
简单来说,正则表达式是对字符串操作的一种逻辑公式,用一些约定好的字符组合对字符串执行检索、匹配、替换等操作。
本文会把学习路径分为两个阶段:
第一阶段,熟悉正则,有一个正确的认识,能够写出简单的正则表达式来操作字符串;
第二阶段,熟练运用正则的一些高级用法,掌握心法,需要时,信手拈来。
第一阶段
需要掌握的内容包括:
- 如何定义一个正则表达式
- 定义了正则,在那些方法中使用
- 元字符
- 字符类 & 字符转义
- 范围 & 量词
- 分支条件
- 反义
如何定义一个正则表达式
有两种方式:
-
通过实例化 RegExp 构造函数
- 有两个参数,第一个是表达式,第二个是修饰符
-
使用字面量把正则写在两个反斜杠中间
- 反斜杠中间是表达式,修饰符紧跟在最后一个 / 后面
DEMO
// 实例化 RegExp 类定义
const reg = new RegExp("\\d",'g');
// 字面量 // 定义
const reg = /\d/g;
let str = "mmcai18is94a99boy";
let result = str.replace(reg," ")
console.log(str)
// 结果:mmcai18is94a99boy
console.log(result)
// 结果:mmcai is a body
// 字符串的 replace 方法不会修改原字符串,会返回一个新的字符串
修饰符
- g:全文搜索,匹配到第一个就结束
- i:忽略大小写
- m:多行搜索
对象属性
- global:对象是否具有标志 g;结果是布尔值
- ignoreCase:对象是否具有标志 i;结果是布尔值
- lastIndex:一个整数,标识开始下一次匹配的字符位置;结果是数字
- multiline:对象是否具有标志 m;结果是布尔值
- source:正则表达式的源文本;结果是字符串
let patt = /[a-z]\d/gim;
patt.global = true;
patt.ignoreCase = true;
patt.multiline = true;
patt.source = "[a-z]\d"
工作空间
其实这里想要表达的是正则表达式可以在那些方法上使用;
应用场景可以分为两种情况
-
正则对象本身具有的一些方法
- test:检索字符串中指定的值。返回 true 或 false
- exec:检索字符串中指定的值。找到返回数组,否则返回 null
- compile:改变正则表达式,不常用
-
一些字符串操作方法当中
- String.replace:替换与正则表达式匹配的字符串
- String.search:检索与正则表达式相匹配的值
- String.split:把字符串分割为字符串数组
- String.match:找到一个或多个正则表达式的匹配
DEMO
// test 判断字符串是否符合我们定义的规则
// 表单验证的时候,可以使用 test 验证:手机号,邮箱,身份证号码,银行卡等数据是否合法
let patt = /1[35789]\d{9}/;
let str = "13588322792"
let flag = patt.test(str);
console.log(flag);
// exec 当没有全局修饰符的时候,函数的作用和 match 函数一样,如果匹配到返回一个数组,否则返回 null
// 把以下代码放入编辑器,查看结果
var str="I love antzone ,this is animate";
var reg=/[a-z]{2}/;
var result = reg.exec(str);
console.log(result);
// result 数组有至少两个值,外加两个属性 input 和 index
- result[0]: 匹配的字符串
- result[1]:存放第一个分组匹配的值,否则为 undefined
- result[2]:存放第二个分组匹配的值,否则没有改项
- result[n]:存放第 n 个分组匹配的值,否则没有该项
result.index = 匹配字符串的索引
result.input = 要匹配字符串完整的引用
// exec 有全局修饰符 g 的时候,此函数返回值同样是一个数组,并且也只能够在字符串中匹配一次。不过此时,此函数一般会和 lastIndex 属性匹配使用,此函数会在 lastIndex 属性指定的字符处开始检索字符串,当 exec()找到与表达式相匹配的字符串时,在匹配后,它将 lastIndex 属性设置为匹配字符串的最后一个字符的下一个位置。可以通过反复调用 exec()函数遍历字符串中的所有匹配,当 exec()函数再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。数组的内容结构和没有 g 修饰符时完全相同。var str="the name 123 and 456";
var reg=/\d/g;
reg.lastIndex=15;
console.log(reg.exec(str));
String.search
search 不执行全局匹配,会忽略修饰符 g。
如果匹配到,返回匹配值所在的索引,否则返回 -1
var str="Visit W3School!"
var r = str.search(/w3school/);
console.log(r);
String.replace
返回一个新的字符串,是替换后得到的新值。
replace 有两个参数:
- 第一个可以是字符串,也可以是正则表达式
- 第二个可以是字符串,也可是 function
如果第二个是字符串,字符串中的 $ 字符有特定的含义
字符 | 说明 |
---|---|
$1…$99 | 子表达式匹配的文本 |
$& | 与 regexp 想匹配的字符串 |
$` | 位于子匹配字符串左侧的文本 |
$’ | 位于子表达式匹配内容右侧的文本 |
$$ | 直接量符号 |
1. 简单用法
var str="Visit Microsoft!"
var res = str.replace(/Microsoft/, "W3School");
console.log(res);
2. 修饰符 g, 全局匹配
var str="Welcome to Microsoft!"
str=str + "We are proud to announce that Microsoft has"
str=str + "one of the largest Web Developers sites in the world."
var res = str.replace(/Microsoft/g, "W3School");
console.log(res);
3. 修饰符 i, 忽略大小写
var text = "javascript Tutorial";
var res = text.replace(/javascript/i, "JavaScript");
console.log(res)
4. 字符中的 $
var name = "Doe, John";
var res = name.replace(/(\w+)\s*, \s*(\w+)/, "$2 $1");
console.log(res)
5.
var name = '"a", "b"';
var res = name.replace(/"([^"]*)"/g,"'$1'");
6. 第二个参数是函数
var name = 'aaa bbb ccc';
var uw=name.replace(/\b\w+\b/g, function(word){return word.substring(0,1).toUpperCase()+word.substring(1);}
);
String.match
匹配到就返回一个数组,数组结构参考上面的 exec 方法,否则返回 null
var str="Hello world!"
var res1 = str.match("world");
var res2 = str.match("World");
console.log(res1);
console.log(res2);
var str="1 plus 2 equal 3"
var res3 = str.match(/\d+/g);
console.log(res3);
String.split
把字符串分割成字符串数组。
返回一个字符串数组。
1.
var str="How are you doing today?"
var res1 = str.split(" ");
var res2 = str.split("");
var res3 = str.split(" ",3);
2.
var words = str.split(/\s+/)
3.
"hello".split("")
元字符
一般情况下,正则表达式的一个字符对应字符串的一个字符。
如果我们想要匹配一类的字符的时候,就可以通过元字符来处理,常用的元字符有:
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
w | 匹配字母或数字或下划线或汉字 |
s | 匹配任意的空白符(包括空格,制表符(Tab),换行符,中文全角空格等) |
d | 匹配数字 |
b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
DEMO
1. 匹配前后都是空格的字符串
let reg = /\b\w+\b/g;
let str = "my name is mmcai";
str.replace(reg,"xx");
2. 修改时间格式 2019 07 18 为 2019/07/18
let reg = /\s/g;
let str = "2019 07 18";
str.replace(reg,"-");
3. 匹配不是特殊符号的字符串
var str="Give 100%!";
var patt1=/\w/g;
4. 匹配以 Is 开头的字符串
var str="Is this his";
var patt1=/^Is/g;
5. 对数字进行全局搜索
var str="Give 100%!";
var patt1=/\d/g;
6. 对字符串结尾是 is 的进行匹配
var str="Is this his";
var patt1=/is$/g;
字符类 & 范围类 & 字符转义
要想查找数字,字母或数字,空白我们可以根据上面一节提到的元字符来匹配。但是如果想匹配的字符集合没有预定义的元字符集合,怎么办?这时候我们就可以通过定义字符类类的形式进行匹配。
例如
[.?!]——匹配表单符号(. 或? 或!)
[abc]——匹配字符 a 或 b 或 c
[aeiou]——匹配任何一个英文元音字母
除了以上方式,我们还可以通过 - 来指定一个字符范围。
例如
[0-9]——匹配 0 到 9 的任意数字,含义和 \d 元字符一样
[a-zA-Z]——匹配 26 个英文字符,大小写都行
特点
- 使用元字符 [] 来构建一个简单的类
- 使用 - 字符定义一个字符范围
- 所谓类就是符合某些特性的对象,一个泛指,不是指某个字符
DEMO
1. 匹配开头是 a 或 b 或 c 紧跟一个数字的字符
var reg =/[abc]\d/g;
var str = "a1b2c3d4";
str.replace(reg,"-");
// result = "---d4";
2. 匹配 a 到 h 之间的字符
var str="Is this all there is?";
var patt1=/[a-h]/g;
字符转义理解起来相对简单,所谓的转义其实是转义我们的元字符,有时候我们需要匹配那些元字符本身的字符串,
就可以通过在元字符前面添加来进行转义;
例如下面一些例子:
// 匹配元字符.
let reg = /\./;
// 匹配元字符 /
let reg = /\//
// 匹配元字符 *
let reg = /\*/
// 匹配字符类的[]
let reg = /\[\]/
// 匹配 \ 本身
let reg = /\\/;
量词
就是表示匹配的数量,我们可以通过一些限定符类指定匹配重复的数量
代码 | 说明 |
---|
- | 重复 0 次或更多次
- | 重复一次或更多次
? | 重复 0 次或一次
{n} | 重复 n 次
{n,} | 重复 n 次或更多次
{n,m} | 重复 n 到 m 次
DEMO
// 匹配 window 后面跟 1 个或多个数字的字符
let reg = /window\d+/;
// 匹配字符的第一个单词
let reg = /^\w+/
// 匹配时间格式为 YYYY-MM-DD 的字符串
let reg = /\d{4}(-\d{2}){2}$/;
let str = "2019-07-18";
// 为了 避免匹配到 "2019-07-1234124" 这样的字符串,添加 $ 结尾符号
reg.test(str)
分支条件
有时候我们匹配的时候,规则不是单一的,可能有多个规则,我们就可以通过分支条件来实现。
比如,我们想要匹配固定电话,有些是三位区号,八位本地号,有些是四位区号,7 位本地号,我们就可以如下写:
let reg = /0\d{2}-\d{8}|0\d{3}-\d{7}/
DEMO
1. 匹配 IP
let reg = /^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/
let str = "192.168.0.253";
reg.test(str);
// 必须添加 ^,否则会匹配 315.168.0.254 这样的字段中的 15.168.0.254 这一段
反义
反义就是取相反,例如 d 是匹配数字,D 就是匹配不是数字的字符,s 匹配空白符字符,S 匹配不是空白符的字符。
在字符类中我们也可以使用 ^ 表示反义,1匹配除 abc 以外的字符,常见的反义代码如下:
代码 | 说明 |
---|---|
W | 匹配任意不是字母、数字、下划线、汉字的字符 |
S | 匹配任意不是空白符的字符 |
D | 匹配任意不是数字的字符 |
B | 匹配不是单词开头或结束位置的字符 |
2 | 匹配除 x 以外的任意字符 |
3 | 匹配除 aeiou 以外的任意字符 |
DEMO
参考匹配 IP 地址里面,是如何匹配. 这个元字符的
- abc ↩
- x ↩
- aeiou ↩