技术分享
首页
  • JavaScript

    • 构造函数和原型
    • Cookie和Session
    • Object.create(null)和{}
    • TypeScript配置
    • typescript入门到进阶
  • 框架

    • Vue-Router
    • React基础入门
  • 其它

    • Http协议
    • 跨域问题总结
  • 分析Promise实现
  • Axios源码分析
  • Webpack原理
  • vueRouter源码分析
  • Vue

    • Vite快速搭建Vue3+TypeScript项目
    • Cordova打包Vue项目的问题
    • Vue将汉字转为拼音,取出首字母
  • JavaScript

    • new Function
  • 后端

    • Node.js中使用Crypto生成Token
    • Body-Parser处理多层对象的问题
  • 其它

    • 项目Demo汇总
    • Vuepress+Vercel搭建个人站点
    • 项目中能用到的
    • husky规范代码提交
  • Mongoose基础
  • Multer文件上传中间件的使用
  • JavaScript

    • 浅谈两数全等
    • JavaScript进制转换
    • 手写bind,apply,call和new
  • 算法

    • 数组去重和排序
    • 数组扁平化
    • 斐波那契数列
  • JavaScript 数据结构
  • 其它

    • webpack面试题
    • vite面试题
    • svg和canvas的优缺点
    • TypeScript面试题
    • Vue常见面试题
  • 计算机网络

    • 数据链路层
    • 网络层
  • Git的使用
  • Nginx的使用
  • CentOS7安装Nginx
  • 正则表达式
  • SEO搜索引擎优化
  • Serverless介绍
友链
GitHub (opens new window)

鑫生活

总有人要赢,为什么不能是我
首页
  • JavaScript

    • 构造函数和原型
    • Cookie和Session
    • Object.create(null)和{}
    • TypeScript配置
    • typescript入门到进阶
  • 框架

    • Vue-Router
    • React基础入门
  • 其它

    • Http协议
    • 跨域问题总结
  • 分析Promise实现
  • Axios源码分析
  • Webpack原理
  • vueRouter源码分析
  • Vue

    • Vite快速搭建Vue3+TypeScript项目
    • Cordova打包Vue项目的问题
    • Vue将汉字转为拼音,取出首字母
  • JavaScript

    • new Function
  • 后端

    • Node.js中使用Crypto生成Token
    • Body-Parser处理多层对象的问题
  • 其它

    • 项目Demo汇总
    • Vuepress+Vercel搭建个人站点
    • 项目中能用到的
    • husky规范代码提交
  • Mongoose基础
  • Multer文件上传中间件的使用
  • JavaScript

    • 浅谈两数全等
    • JavaScript进制转换
    • 手写bind,apply,call和new
  • 算法

    • 数组去重和排序
    • 数组扁平化
    • 斐波那契数列
  • JavaScript 数据结构
  • 其它

    • webpack面试题
    • vite面试题
    • svg和canvas的优缺点
    • TypeScript面试题
    • Vue常见面试题
  • 计算机网络

    • 数据链路层
    • 网络层
  • Git的使用
  • Nginx的使用
  • CentOS7安装Nginx
  • 正则表达式
  • SEO搜索引擎优化
  • Serverless介绍
友链
GitHub (opens new window)
  • Git的使用
  • SEO搜索引擎优化
  • 常用cmd和linux命令
  • Serverless
  • CentOS7安装Nginx
  • GitHub Actions 自动化部署
  • Nginx的使用
  • 正则表达式
    • 编写正则表达式
      • 创建方式有两种
      • 正则表达式由两部分组成
    • 例子
    • 正则的捕获
      • 实现正则捕获的方法
      • 分组捕获和分组引用
      • 正则捕获的贪婪性
    • 常用的正则表达式
      • 1. 验证是否为有效数字
      • 2. 验证密码
      • 3. 验证真实姓名的
      • 4. 验证邮箱的
      • 5.身份证号码
  • 其它
coderly
2020-10-23

正则表达式

# 正则表达式


RegExp: regular expression


学正则就是用来制定规则


用处:用来处理字符串的规则

  • 只能处理字符串
  • 它是一个规则,可以验证字符串是否符合某个规则(test),也可以把字符串中符合规则的内容捕获到(match/exec..)
  • 匹配: test
  • 捕获: exec
let str = 'god good study, day day up!'
let reg = /\d+/
reg.test(str) // => false

str = '2019-9-18'
reg.exec(str) // =>['2019',index:0,inputs: '原始字符串'];
1
2
3
4
5
6

# 编写正则表达式


# 创建方式有两种

// => 字面量创建方式(两个斜杠之间包起来的,就是用来描述规则的元字符)
let reg1 = /\d+/

// => 构造函数模式创建,两个参数:元字符字符串,修饰符字符串(都是字符串)
let reg2 = new RegExp('\\d+')
1
2
3
4
5

# 两种创建正则方式的区别

  • 构造函数因为传递的是字符串,\需要写两个才代表斜杠
let reg = /\d+/g
reg = new RegExp('\\d+', 'g')
1
2
  • 正则表达式中的部分内容是变量存储的值
// 1.两个斜杠中间包起来的都是元字符
let name = "coderly";
reg = /^@"+name+"@$/;
console.log(reg.test("@coderly@")); // =>false

// 2.如果有变量作为正则元字符的一部分,必须用构造函数的方式,因为它传递的规则是字符串
reg = new RegExp("^@"+type+"@$");
1
2
3
4
5
6
7

# 正则表达式由两部分组成

# 元字符

常用元字符:
1、量词元字符,设置出现的次数

  • * :零到多次 \d*
  • + :一到多次 \d+
  • ?:零次或者一次 \d?
  • {n} :出现n次 \d{n}
  • {n, } :出现n到多次 \d{n, }
  • {n, m} :出现n到m次 \d{n, m}

特殊元字符:
2、特殊元字符,单个或者组合在一起代表特殊的含义

  • \ :转义字符(普通 -> 特殊 -> 普通 )
  • . : 除\n( 换行符)以外的任意字符
  • ^ :以哪一个元字符作为开始
  • $ :以哪一个元字符作为结束
  • \n :换行符
  • \d :0~9 之间的一个数字
  • \D :非 0~9 之间的一个数字(大写和小写的意思是相反的)
  • \w :数字、字母、下划线中的任意一个字符
  • \s :一个空白字符(包含空格、制表符、换行符等)
  • \t :一个制表符(一个TAB键:四个空格)
  • | :或,例如x|y:表示x或者y中的一个字符
  • [xyz] :x或者y或者 z 中的一个字符
  • [^xy] :除了x、y以外的任意字符
  • [a-z] :制定a-z这个范围中的任意字符,例如:[0-9a-zA-Z_]=== \w:表示0-9中的任一字符或者a-z中的任一字符或者A-Z中的任一字符或者下划线
  • [^a-z] :上一个的取反“非”
  • () :正则中的分组
  • (?: ) :只匹配不捕获
  • (?=) :正向预查
  • (?!) :负向预查
# 修饰符

常用修饰符(img):

  • i :=>ignoreCase 忽略单词大小写匹配
  • m :=>multiline 可以进行多行匹配
  • g :global 全局匹配
;/A/.test('lalala') // false
;/A/i.test('lalala') //  true
1
2

# 例子

  • ^和$
//  ^/$两个都不加,字符串中包含符合规则的内容即可
let reg1 = /\d+/;// 只要字符串中包含数字就满足条件

//  ^/$两个都加,字符串只能是和规则一致的内容
let reg2 = /^\d+$/
1
2
3
4
5

-\

// => .不是小数点,是除\n外的任意字符
let reg = /^2.3$/;
console.log(reg.test("2@3"));  // => true
console.log(reg.test("2.3"));  // => true

// => 把特殊符号转换为普通的
let reg2 = /^2\.3$/;
console.log(reg2.test("2@3"));  // => false
console.log(reg2.test("2.3"));  // => true

1
2
3
4
5
6
7
8
9
10
  • x|y
// ---- 直接x|y会存在很乱的优先级问题,一般我们写的时候都伴随着小括号进行分组,因为小括号改变处理的优先级  => 小括号:分组
let reg = /^18|29$/
console.log(reg.test('18')) // true
console.log(reg.test('29')) // true
console.log(reg.test('189')) // true
console.log(reg.test('129')) // true
console.log(reg.test('182')) // true
console.log(reg.test('82')) // false

// 现在这样就是只能是18或者29中的一个
let reg2 = /^(18|29)$/
console.log(reg2.test('18')) // true
console.log(reg2.test('29')) // true
console.log(reg2.test('189')) // false
console.log(reg2.test('129')) // false
console.log(reg2.test('182')) // false
console.log(reg2.test('82')) // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • []
// 1. 中括号中出现的字符一般都代表本身的含义
// => 表示匹配括号内的多个
let reg = /[@+]+$/
console.log(reg2.test('@@')) // true
console.log(reg2.test('@+')) // true

// => 表示匹配括号内的一个
let reg2 = /^[@+]$/
console.log(reg2.test('@')) // true
console.log(reg2.test('+')) // true
console.log(reg2.test('@@')) // false
console.log(reg2.test('@+')) // false

// 表示匹配数字,而不是匹配\或者d中的一个,\d在中括号中表示0-9的数字
let reg3 = /^[\d]$/
console.log(reg3.test('d')) // false
console.log(reg3.test('\\')) // false
console.log(reg3.test('9')) // true

// 2. 中括号中不存在多位数

// => 匹配1或者8,而不是18
let reg4 = /^[18]$/
console.log(reg4.test('1')) // true
console.log(reg4.test('8')) // true
console.log(reg4.test('18')) // false

// => 1或者0-2或者9,而不是匹配10-29中的数值
let reg5 = /^[10-29]$/
console.log(reg5.test('1')) // true
console.log(reg5.test('9')) // true
console.log(reg5.test('0')) // true
console.log(reg5.test('2')) // true
console.log(reg5.test('10')) // false

// => 用\ 转义(),没有实现将10-29分组改变优先级,而是()变成了总括号内的一部分。
let reg6 = /^[\(10-29\)]$/
console.log(reg6.test('(')) // true   。此时匹配(发现为true)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 正则的捕获


实现捕获的前提是:当前正则要和字符串匹配(如果不匹配结果捕获是null)

# 实现正则捕获的方法

# 正则RegExp.prototype上的方法

  • exec
let str = 'month06day14huors15'
let reg = /\d+/
console.log(reg.exec(str))
// [ 0: "06", groups: undefined, index: 5, input: "month06day14huors15", length: 1 ]
1
2
3
4
  • 捕获到的结果是 null 或者一个数组
  • 第一项:本次捕获到的内容
  • 其余项:对应小分组本次单独捕获的内容
  • index:当前捕获内容在字符串中的起始索引
  • input:原始字符串
  • 每执行一次 exec 只能捕获到一个符合正则规则的结果

reg.lastIndex:当前正则下一次匹配的起始索引位置

  • 懒惰性捕获的原因:默认 情况下 lastIndex 的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远只是第一个
  • 设置全局匹配修饰符 g 后,第一次匹配到后 lastIndex 会自己修改
  • 所以解决懒惰性就用 全局 g
let str = 'month06day14huors15'
let reg = /\d+/g
console.log(reg.exec(str))
1
2
3

自己实现非懒惰的捕获

!(function() {
  function execAll(str) {
    // 进来后的第一件事,是验证当前正则是否设置了 g, 不设置则不能进行循环捕获,否则会导致死循环
    if (!this.global) return this.exex(str)
    let arr = [],
      res = this.exec(str)
    while (str) {
      arr.push(res)
      res = this.exec(str)
    }
    return arr.length === 0 ? null : arr
  }
  return (RegExp.prototype.execAll = execAll)
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • test
  1. 默认是匹配,但是也可以进行捕获
let str = '2020年06月14日'
let reg = /(\d+)/g
console.log(reg.test(str)) // true
console.log(RegExp.$1) // 2020

console.log(reg.test(str)) // true
console.log(RegExp.$1) // 16

console.log(reg.test(str)) // true
console.log(RegExp.$1) // 14

console.log(reg.test(str)) // true
console.log(RegExp.$1) // 14,存储的是上次捕获的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
  1. RegExp.$1 - RegExp.$9 :获取当前本次正则匹配后,第一个到第九个分组的信息

# 字符串String.prototype上支持正则表达式处理的方法

  • replace
  1. 字符串中实现替换的方法(一般都是伴随正则一起使用的)

案例:把时间字符串进行处理

let time = '2020-06-14' // 变为 2020年06月14日
let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/g

// 方法一
time = time.replace(reg, '$1年$2月$3日')
console.log(time) // 2020年06月14日

// 还可以这样处理
// 1. 首先拿 reg 和 time 进行匹配捕获,能匹配到几次就会把传递的函数执行几次(而且是匹配一次就执行一次)
// 2. 不仅把方法执行,而且 replace 还给方法传递了实参信息(和 exec 捕获的内容一致的信息:大正则匹配的内容,小分组匹配的信息)
// 3. 使用函数时,当前大正则匹配的内容替换为函数中返回的内容
time = time.replace(reg, (_, ...arr) => {
  console.log(_) //2020-06-14
  console.log(arr) //  ["2020", "06", "14", 0, "2020-06-14"]
  return ` ${arr[0]}年${arr[1]}月${arr[2]}日`
})
console.log(time) // 2020年06月14日
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

案例 2:单词首字母大写

let str = 'good good study, day day up!'
let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g
str = str.replace(reg, (_, ...arg) => {
  let $1 = arg[0].toUpperCase()
  return $1 + _.substring(1)
})
1
2
3
4
5
6

案例 3:验证一个字符串中出现最多的字母,多少次?

let str = 'coderly,day day up!'
str = str
  .split('')
  .sort((a, b) => a.localeCompare(b))
  .join('')
let reg = /([a-zA-Z])\1+/g
let ary = str.match(reg)
ary.sort((a, b) => b.length - a.length)
console.log(ary) // ["ddd", "yyy", "aa"]
1
2
3
4
5
6
7
8
9
  • match
    字符串的 match 匹配到的是一个数组
'month06day14huors15'.match(/\d+/)
// [0: "06", groups: undefined, index: 5, input: "month06day14huors15", length: 1]

'month06day14huors15'.match(/\d+/g)
// ["06", "14", "15"]
1
2
3
4
5
  • splite

# 分组捕获和分组引用

# 分组捕获

  • 第一项: 大正则匹配的结果
  • 其余项: 每一个小分组单独匹配捕获的结果
  • 如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于 ?: 来处理
  • ?: 只匹配不捕获,(?:\d{2})
let str = '2020-06-14'
let reg = /(\d{4})-(\d{2})-(\d{2})/
console.log(reg.exec(str))
console.log(str.match(reg))
//  [ 0: "2020-06-14", 1: "2020", 2: "06", 3: "14", groups: undefined, index: 0, input: "2020-06-14", length: 4 ]
1
2
3
4
5
  • 既要捕获到 {\d},也要把里面的数字也单独捕获到
let str = '{2020}年{06}月{14}日'
let reg = /{(\d+)}/g

let arrBig = [],
  arrSmall = [],
  res = reg.exec(str)
while (res) {
  let [big, small] = res
  arrBig.push(big)
  arrSmall.push(small)
  res = reg.exec(str)
}
console.log(arrBig)
console.log(arrSmall)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 分组引用

  • 分组引用就是通过 "\数字" 让其代表和对应分组出现一模一样的内容;
let res = 'book'
1

# 正则捕获的贪婪性

  • 默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
  • 取消正则捕获贪婪性:在量词元字符后面设置 ? ,此时按照正则匹配的最短结果来获取
let str = '2020年06月14日'
let reg = /\d+/g
console.log(str.match(reg)) //  ["2020", "06", "14"]:贪婪性,默认按匹配最长捕获

let str = '2020年06月14日'
let reg = /\d+?/g
console.log(str.match(reg)) // ["2", "0", "2", "0", "0", "6", "1", "4"]:取消贪婪性,按匹配最短捕获
1
2
3
4
5
6
7

# ? 在正则中的作用

  • 左边是非量词元字符:本身代表量词元字符,出现 0-1 次
  • 左边是量词元字符:取消捕获时候的贪婪性
  • (?:) :只匹配不捕获
  • (?=):正向预查
  • (?!):负向预查

# 常用的正则表达式


# 1. 验证是否为有效数字

  • 规则分析,(0, 1, 12, 12.5, 12.0, -1, -12.5, +9) (09不是有效数字)
      1. 可能出现+、-,也可能不出现。(+|-)?
      1. 一位 0-9 都可以,多为首位不能为 0。(\d | ([1-9]\d+))
      1. 小数部分可能有可能没有,一旦有后面必须有小数点+数字。(\.\d+)?
let reg = /^(+|-)?(\d|([1-9]\d+))(\.\d+)?$/
1

# 2. 验证密码

  • 规则分析:
      1. 数字、字母、下划线 \w
      1. 6~16 位 {6,16}
let reg = /^\w{6,16}$/
1

# 3. 验证真实姓名的

  • 规则分析:
      1. 汉字 /^[\u4E00-\u9FA5]$/
      1. 名字长度 2-10 位
      1. 可能有译名 ·汉字 /^(·[\u4E00-\u9FA5]){2,10}{0,2}$/
let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/
1

# 4. 验证邮箱的

  • 规则分析:
      1. 开头是数字字母下划线(1 到多位)/^\w$/
      1. 还可以是 - 数字字母下划线或者 .数字字母下划线,整体零次到多次
    • 3.邮箱的名字由“数字、字母、下划线、-、.”几部分组成,但是-和.不能连续出现也不能作为开始,(liu-yu-x,liu.yu.x,liu-yu.x) \w+((-\w+)|(\.\w+))*
      1. @后面紧跟着:数字、字母(1 多多位)@[A-Za-z0-9]+
let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-))[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
1

# 5.身份证号码

【注意】一代身份证 15 位现在用不了

  • 规则分析:
      1. 一共十八位
      1. 最后一位可能是 X
// 1. 身份证前六位: 省市县
// 2.中间八位:年月日
// 3. 最后四位:
//      最后一位 => x 或者数字
//      倒数第二位 =>偶数 女,奇数 男
//      其余的是通过算法算出来的

// let reg = /^d{17}(\d|x)$/;
// => 小括号分组的第二个作用:分组捕获,不仅可以把大正则匹配的信息捕获到,还可以单独捕获到每个小分组的内容
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|x)$/;
reg.exec("130828199012040617")
结果:
["130828199012040617", "130828", "1990", "12", "04", "1", "7", index: 0, input: "130828199012040617", groups: undefined]
// 捕获结果是一个数组,包含每一个小分组单独获取的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
上次更新: 2021/09/13, 15:11:59
Nginx的使用

← Nginx的使用

最近更新
01
css
09-13
02
html
09-13
03
README
09-13
更多文章>
Theme by Vdoing | Copyright © 2021-2021 coderly | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式