如果再给我一次机会,我选择学会正则表达式!!!

264 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

正则表达式

背景

在日常开发中,我们经常会遇到使用正则表达式的场景,比如一些常见的表单校验,会让你匹配用户输入的手机号或者身份信息是否规范,这就可以用正则表达式去匹配。相信大多数人在碰到这种场景的时候都是直接去网上找,然后一顿cv操作就过去了,下次再遇到相同的问题时,又是重复一遍之前的操作。

正则作为一个用途比较广泛的技术,理应被我们所掌握,而不是每次都只有在需要用到的时候临时去网上查找,如果出了问题你也找不到问题出在哪。我们今天的课程就会教大家如何去使用正则表达式,不光能看懂别人写的,也可以自己去写一些常见的正则表达式。

什么是正则表达式?

  • 正则表达式是用于匹配字符串中字符组合的模式。许多语言都支持正则表达式,在 JavaScript 中,正则表达式也是对象。

  • 就是用来匹配字符串的规则

    判断一个字符串中是否包含有某个字符或者某个字符串

    找出字符串'000000O0000000'中是否有大写字母O
    

    判断用户输入的手机号或者密码是否符合校验规则

正则表达式的语法

语法

定义一个正则表达式

const 变量名 = /表达式/

比如:

const reg = /前端/
  • test() - 用来查看正则表达式与指定的字符串是否匹配
const reg = /前端/
reg.test('前端大法好') // true
  • exec() - 查找符合规则的字符串
const reg = /前端/
const str = '前端大法好,前端工资高,就业前景好'
console.log(reg.exec(str)) // ['前端', index: 1, input: '前端大法好,前端工资高,就业前景好', groups: undefined]
  • replace() - 用来替换字符串中符合规则的字符
const reg = /java/
const str = 'java大法好'
str.replace(reg, '前端') // '前端大法好'
  • match() - 可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
const reg = /前端/g
const str = '前端大法好,前端工资高,就业前景好'
str.match(reg) // ['前端', '前端']

修饰符

修饰符约束正则执行的某些细节行为,如是否区分大小写、是否全局匹配

修饰符说明
i单词 ignore 的缩写,正则匹配时字母不区分大小写
g单词 global 的缩写,匹配所有满足正则表达式的结果
// i 
console.log(/a/.test('A')) // false
console.log(/a/i.test('A')) // true// g
const str = 'hello world'
str.replace(/o/, '_') // hell_ world
str.replace(/o/g, '_') // hell_ w_rld

元字符

普通字符

大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。

元字符

是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能

比如:匹配26个英文字母,用普通字符表示 abcde...xyz,但是用元字符表示的话,只需要 [a-z]

边界符

(1)单词边界

找出某句话中的某个单词,例如:The cat scattered his food all over the room.

想找到cat这个单词,但是如果只是使用/cat/这个正则,就会同时匹配到catscattered这两处文本,这时候就可以用到单词边界\b,它其实匹配的是能构成单词的字符(\w)和不能构成单词的字符(\W)中间的那个位置。

// 这个正则就只会匹配到单词cat而不会匹配到scattered了
const reg = /\bcat\b/

(2)字符串边界

边界符说明
^表示匹配行首的文本
$表示匹配行尾的文本
const reg = /^a/i // 以a开头
console.log(reg.test('a')); // true
console.log(reg.test('abc')); // true
console.log(reg.test('bcd')); // false
console.log(reg.test('Abc')); // true


const reg = /c$/ // 以c结尾
console.log(reg.test('abc')); // true
console.log(reg.test('bcd')); // false
```

注意:如果^ 和 $ 在一起,表示必须是精确匹配

const reg = /^ac$/ // ^ $ 再一块的时候表示精确匹配
console.log(reg.test('a')); // true
console.log(reg.test('aaa')); // false

量词:表示某个模式出现的次数

量词说明
*重复0次或更多次
+重复1次或更多次
?重复0次或1次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次
// *: 表示0次或更多次
const reg1 = /^a*$/
console.log(reg1.test('a')); // true
console.log(reg1.test('')); // true
console.log(reg1.test('aaa')); // true

// +: 表示1次或更多次
const reg2 = /^a+$/
console.log(reg2.test('a')); // true
console.log(reg2.test('')); // false
console.log(reg2.test('aaa')); // true

// ?: 表示0次或1次
const reg3 = /^a?$/
console.log(reg3.test('a')); // true
console.log(reg3.test('')); // true
console.log(reg3.test('aaa')); // false// {n}: 表示只能有n次
const reg4 = /^a{3}$/
console.log(reg4.test('a')); // false
console.log(reg4.test('')); // false
console.log(reg4.test('aaa')); // true
console.log(reg4.test('aaaa')); // false// {n,}: 表示大于等于n次
const reg5 = /^a{2,}$/
console.log(reg5.test('a')); // false
console.log(reg5.test('')); // false
console.log(reg5.test('aaa')); // true
console.log(reg5.test('aa')); // true// {n,m}: n-m次
const reg6 = /^a{2,4}$/
console.log(reg6.test('a')); // false
console.log(reg6.test('')); // false
console.log(reg6.test('aaa')); // true
console.log(reg6.test('aa')); // true
console.log(reg6.test('aaaaaa')); // false

注意:逗号两侧不能出现空格

字符类

(1)[ ] 匹配字符集合

// 后面的字符串只要包含 abc 中任意一个字符
const reg1 = /[abc]/
console.log(reg1.test('andy')) // true
console.log(reg1.test('baby')) // true
console.log(reg1.test('cry')) // true
console.log(reg1.test('dad'))  // false// 使用连字符 - 表示一个范围
const reg2 = /[a-z]/ // 匹配26个英文小写字母中的任意一个
const reg3 = /[a-zA-Z]/ // 匹配26个英文字母中的任意一个,大小写都可以
const reg4 = /[0-9]/ // 匹配0-9中的数字// []里面加上^表示取反,注意要写到中括号里
const reg5 = /[^a-z]/ // 表示匹配除了26个小写字母以外的字符

(2). 匹配除换行符之外的任意单个字符

const reg = /./ // 匹配除换行符之外的任何单个字符
reg.test('aaa') // true
reg.test('123') // true
reg.test('\n') // false

(3)预定义:指的是某些常见模式的简写方式。

| 预定类 | 说明                                  |
| --- | ----------------------------------- |
| \d  | 匹配0-9之间的任意数字,相当于[0-9]               |
| \D  | 匹配0-9以外的任意字符,相当于[ ^0-9]             |
| \w  | 匹配任意的字母,数字和下划线,相当于[a-zA-Z0-9_]      |
| \W  | 匹配除字母,数字和下划线以外的字符,相当于[ ^a-zA-Z0-9_] |
| \s  | 匹配空格(包含换行、空格、制表符等),相当于[\t\r\n\v\f]  |
| \S  | 匹配非空格的字符,相当于[ ^\t\r\n\v\f]          |

分组和分支结构

分组

我们知道/a+/匹配连续出现的“a”,而要匹配连续出现的“ab”时,需要使用/(ab)+,其中括号是提供分组功能,使量词+作用于“ab”这个整体

const reg = /(ab)+/g;
const str = "abba abbb babbba";
str.replace(reg, 'cd') // 'cdba cdbb bcdbba'

分组捕获:例如将YYYY-MM-DD格式的日期替换成MM/DD/YYYY

YYYY-MM-DD的匹配模式为 /\d{4}-\d{2}-\d{2}/,是将整个日期作为一个组(group)匹配起来。 我们把这样的叫Group0

这个时候,如果我们上括号/(\d{4})-(\d{2})-(\d{2})/,那么分组就是下面的情况:

YYYY-MM-DD   Group0
YYYY         Group1
MM           Group2
DD           Group3

想要获取每个分组匹配的内容该怎么获取呢?可以通过$符号获取,比如$1 代表YYYY$2代表MM,所以完整的代码应该如下:

const reg = /(\d{4})-(\d{2})-(\d{2})/
const date = "2023-01-05"
console.log(reg.test(date)) // true
console.log(date.replace(reg, '$2/$3/$1')) // 01/05/2023
分支结构

分支结构类似逻辑操作中的或操作,表示匹配规则1或者规则2

const reg = /(java)|(前端)/;
const str1 = "前端大法好";
const str2 = "java大法好"
reg.test(str1) // true
reg.test(str2) // true

案例

  1. 密码匹配(6-16位字母、数字或者下划线)
const reg = /^[a-zA-Z0-9_]{6,16}$/
  1. 匹配16进制颜色值(比如:#f0f0f0, #fff)
const reg = /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/
  1. 匹配24小时制的时间(比如:23:59,08:29)
const reg = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/;
  1. 手机号码脱敏
// 15812345678 => 158****5678
const reg = /(^1[3-9]\d)\d{4}(\d{4})/
const mobile = "15812345678"
console.log(reg.test(mobile)) // true
console.log(mobile.replace(reg, '$1****$2')) // 158****5678

常用的正则的工具

  1. vscode插件:any-rule

    功能:支持一键生成常见的正则表达式

  2. regexper.com/

    功能:可视化自己写的正则表达式