阅读 955

玩转js正则表达式

      正则表达式是用于匹配字符串中字符组合的模式,即实现对字符串中的信息进行查找、替换和提取操作。下面是我对js中正则表达式的整理与总结。如果大家发现文章中有问题,欢迎大家在评论中指正。

1. 正则常见语法

1.1 匹配模式

Example:
// 获取所有匹配项,并忽略大小写
const testString = 'test Test tEsT abdskxc ioewhsnc'
const reg = /test/gi
console.log(testString.match(reg)) // [ 'test', 'Test', 'tEsT' ]
复制代码

1.2 基本元字符和特殊字符元字符

Example:
// 使用操作符 |
const reg = /yes|no|maybe/
// 匹配任意字符 使用 . 作为任何字符的占位符
const regexp = /.at/gi
const testString = 'cat Bat mat DOG egg FAT cupcake sing'
console.log(testString.match(regexp)) // [ 'cat', 'Bat', 'mat', 'FAT' ]
// 使用字符类 用来定义匹配的一组字符 []
const testReg = /[cmf]at/g
console.log(testString.match(testReg)) // [ 'cat', 'mat' ]
// 匹配字母表中的字母
const regTest = /[a-d]at/
const str1 = 'cat', str2 = 'fat', str3 = 'bat'
console.log(regTest.test(str1), regTest.test(str2), regTest.test(str3)) // true false true
// 匹配特定的数字和字母
const reg1 = /[a-z0-9]/gi
const testString1 = 'sagiga46323'
console.log(reg1.test(testString1)) // true
// 匹配单个未知字符
const reg2 = /[^aeiou]/gi
// 匹配所有字母和数字
const longReg = /[A-Za-z0-9_]+/
const shortReg = /\w+/
const num = '46313'
const str4 = 'dsiohdkcsds'
console.log(longReg.test(num), shortReg.test(num), longReg.test(str4), shortReg.test(str4)) // true true true true
// 除了字母和数字,其他的都要匹配
const reg3 = /\w/gi
const str5 = '!_$!!'
const str6 = 'sj456AyTB'
console.log(reg3.test(str5)) // true
console.log(reg3.test(str6)) // true
// 匹配所有数字
const digitReg = /\d/g
const strDigit = 'The shirt is $35.12'
console.log(strDigit.match(digitReg)) // [ '3', '5', '1', '2' ]
// 匹配所有非数字
const nonDigitReg = /\D/g
const nonStr = '463 dshkfsd'
console.log(nonStr.match(nonDigitReg)) // [' ', 'd', 's', 'h', 'k', 'f', 's', 'd']
// 匹配空格
const senReg = /\s/g
const sentence = 'I like mike'
console.log(sentence.match(senReg)) // [ ' ', ' ' ]
// 匹配非空格
const nonsenReg = /\S/g
console.log(sentence.match(nonsenReg)) // ['I', 'l', 'i', 'k', 'e', 'm', 'i', 'k', 'e']
复制代码

1.3 量词

  量词表示匹配多少个目标对象,精确匹配长度使用{}。

Example:
// 匹配一行中出现一次或多次的字符
const oneOrMoreReg = /a+/gi
const oneOrMoreStr = 'sahiohankdahka'
console.log(oneOrMoreStr.match(oneOrMoreReg)) // [ 'a', 'a', 'a', 'a' ]
// 匹配连续出现零次或多次字符
const zeroOrMoreReg = /hi*/gi
const zeroOrMoreStr = 'ahiadahdisdhixc'
const zeroOrMoreStr2 = 'adakskmd'
console.log(zeroOrMoreStr.match(zeroOrMoreReg), zeroOrMoreStr2.match(zeroOrMoreReg)) // [ 'hi', 'h', 'hi' ] null
// 惰性匹配
// 没人情况下,正则表达式是贪婪的,即匹配满足给定要求的字符串的最长部分
// 使用 ? 阻止贪婪模式
const greedyReg = /c[a-z]*t/gi
const lazyReg = /c[a-z]*?t/gi
const testStr7 = 'catshidtasji'
console.log(testStr7.match(greedyReg), testStr7.match(lazyReg)) // [ 'catshidt' ] [ 'cat' ]
// 匹配字符数
const regular = 'hihi'
const superHi = 'hadiojknejodmc'
const regx = /hi{1,4}/
console.log(regx.test(regular), regx.test(superHi)) // true false
// 匹配最低个数的字符数
const strHi = 'hiiiii'
const hiReg = /hi{3,}/
console.log(hiReg.test(regular), hiReg.test(superHi), hiReg.test(strHi)) // false false true
// 匹配精确的字符数
const exactReg = /hi{4}/
console.log(exactReg.test(strHi), exactReg.test(regular)) // true false
// 匹配0次或1次
const colSpell = 'Colour'
const colSpelling = 'color'
const colReg = /colou?r/i
console.log(colReg.test(colSpell), colReg.test(colSpelling)) // true true
复制代码

1.4 边界

Example:
// 匹配起始字符串
const str8 = 'hello world'
const str9 = 'world is beautiful, hello'
const startReg = /^hello/
console.log(startReg.test(str8), startReg.test(str9)) // true false
// 匹配结束字符串
const endReg = /hello$/
console.log(endReg.test(str8), endReg.test(str9)) // false true
复制代码

1.5 分组

Example:
console.log(`ashinmdnkbdkchbjduigh`.replace(/h(inm|bj)d/g, '-')) // as-nkbdkc-uigh
console.log('2021-01-08'.replace(/(\d{4})\-(\d{2})\-(\d{2})/g, '$2/$3/$1')) // 01/08/2021
let reg = /\d{4}(\-|\/|.)\d{1,2}\1\d{1,2}/
console.log(reg.test('2021-01-08'), reg.test('2021-01.08')) // true false
// 正向前瞻 后面要有xx
console.log('4a5d6sa4da5c1x'.replace(/\w(?=\d)/g, '-')) // 4-5-6s-4d-5-1x
// 负向前瞻 后面不能有xx 
console.log('4a5d6sa4da5c1x'.replace(/\w(?!\d)/g, '-')) // -a-d--a--a-c--
// 正向后顾 前面要有xx
const regexp1 = /(?<=\$)\d+/u
const str = 'shirt $463'
console.log(regexp1.exec(str)) // [ '463', index: 7, input: 'shirt $463', groups: undefined ]
// 负向后顾 前面不能有xx
const regexp2 = /(?<!\$)\d+/u 
console.log(regexp2.exec(str)) // [ '63', index: 8, input: 'shirt $463', groups: undefined ]
复制代码

1.6 大小写转换

1.7 优先权顺序

  下面从最高优先级到最低优先级列出优先权的顺序:

         (1) 转义符:\

         (2) 圆括号和方括号:(), (?:), (?=), []

         (3) 限定符: *, +, ?, {n}, {n,}, {n,m}

         (4) 位置和顺序: ^, $, \anymetacharacter

         (5) “或”操作: |

2.js的RegExp对象

  在js中,正则表达式是用RegExp对象表示,其有两种写法:一是字面量写法,二是构造函数写法。

2.1 构造函数

let reg = new RegExp('<%[^%>]+%>', 'g');
复制代码

2.2 字面量

let reg = /<%[^%>]+%>/g
复制代码

2.3 js中正则表达式函数

2.3.1 String.prototype.search方法

  用来找出字符串中某个字符串首次出现的位置,返回找到首个字符的位置,不存在则返回-1。该方法不执行全局匹配。它将忽视修饰符g,并总是从字符串的开始进行检索。

console.log('abchello'.search(/hello/)) // 3
console.log('abchell'.search(/hello/)) // -1
复制代码
2.3.2 String.prototype.replace方法

  用来替换字符串中的子串,其传入的参数可以是String、Number或回调函数function。

console.log('abchello'.replace(/hello/, 'hi')) // abchi


let str = 'sgudcbsjbckankdanknfnsndndcksnck'
const arr = str.split(/\s*/) // 将字符串转换成数组
const str2 = arr.sort().join('') // 排序,然后转成字符串

let value = ''
let index = 0
str2.replace(/(\w)\1*/g, function($0, $1) { // 匹配字符
  if (index < $0.length) {
    index = $0.length // index 出现次数
    value = $1 // value 对应的字符
  }
})
console.log(`最多的字符: ${value}, 重复的次数: ${index}`) // 最多的字符: n, 重复的次数: 7
复制代码
2.3.3 String.prototype.test方法

  用来测试字符串中是否存在子字符串。当使用该方法有修饰符g时,那么正则会记住lastIndex该属性,并在下一次执行的时候从lastIndex处开始检测。

console.log(/hello/.test('abchello')) // true
复制代码
2.3.4 String.prototype.split方法

  用来把一个字符串拆分为多个子串。

console.log('qwehelloasdfhellozxvnmxhellohkjp'.split(/hello/)) // [ 'qwe', 'asdf', 'zxvnmx', 'hkjp' ]
复制代码
2.3.5 String.prototype.match方法

  将字符串中的子字符串捕获到一个数组中,默认情况下,只捕获一个结果到数组中。

console.log('qwehelloasdfhellozxvnmxhellohkjp'.match(/hello/)) // [ 'hello' ]
console.log('qwehelloasdfhellozxvnmxhellohkjp'.match(/hello/g)) // [ 'hello', 'hello', 'hello' ]
复制代码
2.3.6 String.prototype.exec方法

  该方法与字符串的match方法类似,也是从字符串中捕获满足条件的字符串到数组中,但该方法一次只能捕获一个子字符串到数组中。

console.log(/hello/g.exec('qwehelloasdfhellozxvnmxhellohkjp')) // [ 'hello' ]
复制代码

  在RegExp对象中有一个lastIndex属性用来表示下一次从哪个位置开始捕获,当每一次exec方法执行时,lastIndex就会向后推,直到找不到匹配的字符返回null后,又继续从头开始捕获。

let reg = /hello/g
console.log(reg.lastIndex) // 用来便利捕获字符串中的子串 0
reg.exec('qwehelloasdfhellozxvnmxhellohkjp')
console.log(reg.lastIndex) // 8
reg.exec('qwehelloasdfhellozxvnmxhellohkjp')
console.log(reg.lastIndex) // 17
reg.exec('qwehelloasdfhellozxvnmxhellohkjp')
console.log(reg.lastIndex) // 28
reg.exec('qwehelloasdfhellozxvnmxhellohkjp')
console.log(reg.lastIndex) // 0
复制代码

3.常见的具体实例

3.1 实例一:判断是否是一个有效的手机号码

let str = '13807562276'
let reg = new RegExp('1[3578]\\d{9}') // 匹配纯数字1次或多次
console.log(reg.test(str)) // true
str = '16794232379'
console.log(reg.test(str)) // false
复制代码

3.2 提取文本中的所有7位有效的数字

let text = '文本内容,1234567,花费4564613元费用,来完成9745638个计划'
let res = new RegExp('\\d{7}', 'g')
while ((result = res.exec(text)) != null) {
  console.log(result, res.lastIndex)
}
// 结果
// [
//   '1234567',
//   index: 5,
//   input: '文本内容,1234567,花费4564613元费用,来完成9745638个计划',
//   groups: undefined
// ] 12
// [
//   '4564613',
//   index: 15,
//   input: '文本内容,1234567,花费4564613元费用,来完成9745638个计划',
//   groups: undefined
// ] 22
// [
//   '9745638',
//   index: 29,
//   input: '文本内容,1234567,花费4564613元费用,来完成9745638个计划',
//   groups: undefined
// ] 36
复制代码

3.3 用户名正则

// 用户名,4 - 16 位(包括字母、数字、下划线、减号)
const reg = /^[a-zA-Z0-9_-]{4,16}$/;
console.log(reg.test('dabai')); // true
复制代码

3.4 密码强度正则

// 最少6位,最长16位,包括至少一个大写字母,一个小写字母,一个数字,一个特殊字符
let reg = /^.*(?=.{6,16})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*?\(\)]).*$/;;
console.log(reg.test('daBai2021*')) // true
复制代码

3.5 身份证号正则

let reg = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
console.log(reg.test('11010519780603375X')) // true
复制代码

3.6 十六进制颜色正则

let reg = /^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
console.log(reg.test('#fcfcfc'), reg.test('#fff')) // true true
复制代码

3.7 整数正则

// 正整数正则 负整数正则 整数正则
let posReg = /^\d+$/, negReg = /^-\d+$/, intReg = /^-?\d+$/
console.log(posReg.test('613'), negReg.test('-7946'), intReg.test('5463')) // true true true
复制代码

3.8 数字正则

// 正数正则 负数正则 数字正则
// 数字可以是整数也可以是浮点数
let posReg = /^\d*\.?\d+$/, negReg = /^-\d*\.?\d+$/, numReg = /^-?\d*\.?\d+$/
console.log(posReg.test('56.12'), negReg.test('-78.16'), numReg.test('46123.56')) // true true true
复制代码

3.9 日期正则

// 简单判定
let reg = /^\d{4}(\-)\d{1,2}\1\d{1,2}$/
console.log(reg.test('2021-01-08')) // true
// 复杂判定
let reg2 = /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/
console.log(reg2.test('2021-01-08')) // true
复制代码

3.10 包括中文正则

let reg = /[\u4E00-\u9FA5]/
console.log(reg.test('大白')) // true
复制代码

3.11 车牌号正则

let reg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/
console.log(reg.test('赣A56896')) // true
复制代码

3.12 URL正则

let reg = /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
console.log(reg.test('http://www.baidu.com')) // true
复制代码

3.13 QQ号码正则

let reg = /^[1-9][0-9]{4,10}$/
console.log(reg.test('56213147')) // true
复制代码

3.14 微信号正则

// 6-20位,以字母开头,包含字母、数字、减号、下划线
let reg = /^[a-zA-Z]([a-zA-Z0-9-_]{5,19})+$/
console.log(reg.test('dabai456_sh-2021')) // true
复制代码

3.15 邮箱email正则

let reg = /^([A-Za-z0-9_\-\.])+@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/
console.log(reg.test('23233232@qq.com')) // true
复制代码

3.16 IPv4地址正则

let reg = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
console.log(reg.test('192.168.47.26')) //true
复制代码

参考来源

  1. 《正则表达式必知必会》
  2. developer.mozilla.org/zh-CN/docs/…

最后

如果喜欢我的文章请 " 点赞 " " 评论 " " 关注 ",大家的支持就是我坚持下去的动力!若是以上内容有任何错误或者不准确的地方,欢迎留言指出,若你有更好的想法,也欢迎一起交流学习!