就因为这三个知识点,我彻底学废了”正则表达式“

栗子详解


学习完位置相关的知识,我们来做一下开头的几个题目试试

题目1:数字的千分位分割法

将123456789转化为123,456,789

观察题目的规律就是从后往前,每三个数字前加一个逗号,(需要注意的是开头不需要加逗号,)。是不是很符合 (?=p)的规律呢?p可以表示每三个数字,要添加的逗号所处的位置正好是(?=p)匹配出来的位置。

第一步,尝试先把后面第一个逗号弄出来

let price = ‘123456789’

let priceReg = /(?=\d{3}$)/

console.log(price.replace(priceReg, ‘,’)) // 123456,789

复制代码

第二步,把所有的逗号都弄出来

要把所有的逗号都弄出来,主要要解决的问题是怎么表示三个数字一组,也就是3的倍数。我们知道正则中括号可以把一个p模式变成一个小整体,所以利用括号的性质,可以这样写

let price = ‘123456789’

let priceReg = /(?=(\d{3})+$)/g

console.log(price.replace(priceReg, ‘,’)) // ,123,456,789

复制代码

第三步,去掉首位的逗号,

上面已经基本上实现需求了,但是还不够,首位会出现,那怎么把首位的逗号去除呢?想想前面是不是有一个知识正好满足这个场景? 没错(?!p),就是他了,两者结合就是从后往前每三个数字的位置前添加逗号,但是这个位置不能是^首位。

let price = ‘123456789’

let priceReg = /(?!^)(?=(\d{3})+$)/g

console.log(price.replace(priceReg, ‘,’)) // 123,456,789

复制代码

题目2:手机号3-4-4分割

将手机号18379836654转化为183-7983-6654

有了上面数字的千分位分割法,做这个题相信会简单很多,也就是从后往前找到这样的位置:

每四个数字前的位置,并把这个位置替换为-

let mobile = ‘18379836654’

let mobileReg = /(?=(\d{4})+$)/g

console.log(mobile.replace(mobileReg, ‘-’)) // 183-7983-6654

复制代码

题目3:手机号3-4-4分割扩展

将手机号11位以内的数字转化为3-4-4格式

回想一下这样的场景,有一个表单需要收集用户的手机号,用户是一个个数字输入的,我们需要在用户输入11位手机号的过程中把其转化为3-3-4格式。即

123 => 123

1234 => 123-4

12345 => 123-45

123456 => 123-456

1234567 => 123-4567

12345678 => 123-4567-8

123456789 => 123-4567-89

12345678911 => 123-4567-8911

复制代码

这样用(?=p)就不太合适了,例如1234就会变成-1234。 想想前面的知识点有适合处理这种场景的吗?是的(?<=p)

第一步, 将第一个-弄出来

const formatMobile = (mobile) => {

return String(mobile).replace(/(?<=\d{3})\d+/, ‘-’)

}

console.log(formatMobile(123)) // 123

console.log(formatMobile(1234)) // 123-

复制代码

将第二个-弄出来

将第一个-弄出来之后,字符的长度多了一位,原本1234567(这个位置插入-)8,要变成往后移一位

const formatMobile = (mobile) => {

return String(mobile).slice(0,11)

.replace(/(?<=\d{3})\d+/, ($0) => ‘-’ + $0)

.replace(/(?<=[\d-]{8})\d{1,4}/, ($0) => ‘-’ + $0)

}

console.log(formatMobile(123)) // 123

console.log(formatMobile(1234)) // 123-4

console.log(formatMobile(12345)) // 123-45

console.log(formatMobile(123456)) // 123-456

console.log(formatMobile(1234567)) // 123-4567

console.log(formatMobile(12345678)) // 123-4567-8

console.log(formatMobile(123456789)) // 123-4567-89

console.log(formatMobile(12345678911)) // 123-4567-8911

复制代码

题目4:验证密码的合法性

密码长度是6-12位,由数字、小写字符和大写字母组成,但必须至少包括2种字符

题目由三个条件组成

① 密码长度是6-12位

② 由数字、小写字符和大写字母组成

③ 必须至少包括2种字符

第一步写出条件①和②和正则

let reg = /1{6,12}$/

复制代码

第二步,必须包含某种字符(数字、小写字母、大写字母)

let reg = /(?=.*\d)/

// 这个正则的意思是,匹配的是一个位置,这个位置需要满足任意数量的符号,紧跟着是个数字,注意它最终得到的是个位置,而不是数字或者是数字前面有任意的东西

console.log(reg.test(‘hello’)) // false

console.log(reg.test(‘hello1’)) // true

console.log(reg.test(‘hel2lo’)) // true

// 其他类型同理

复制代码

第三步,写出完整的正则

必须包含两种字符,有下面四种排列组合方式

① 数字和小写字母组合

② 数字和大写字母组合

③ 小写字母与大写字母组合

④ 数字、小写字母、大写字母一起组合(但其实前面三种已经覆盖了第四种了)

// 表示条件①和②

// let reg = /((?=.\d)((?=.[a-z])|(?=.*[A-Z])))/

// 表示条件条件③

// let reg = /(?=.[a-z])(?=.[A-Z])/

// 表示条件①②③

// let reg = /((?=.\d)((?=.[a-z])|(?=.[A-Z])))|(?=.[a-z])(?=.*[A-Z])/

// 表示题目所有条件

let reg = /((?=.\d)((?=.[a-z])|(?=.[A-Z])))|(?=.[a-z])(?=.*[A-Z])2{6,12}$/

console.log(reg.test(‘123456’)) // false

console.log(reg.test(‘aaaaaa’)) // false

console.log(reg.test(‘AAAAAAA’)) // false

console.log(reg.test(‘1a1a1a’)) // true

console.log(reg.test(‘1A1A1A’)) // true

console.log(reg.test(‘aAaAaA’)) // true

console.log(reg.test(‘1aA1aA1aA’)) // true

复制代码

2. 字符串匹配原来这么简单

===============

两种模糊匹配


正则如果只有精确匹配,那么便完全没有了意义

横向

一个正则可匹配的字符串的长度不是固定的,可以是多种情况,通过量词+、*、?、{m,n},可实现横向匹配

let reg = /ab{2,5}c/g

let str = ‘abc abbc abbbc abbbbc abbbbbc abbbbbbc’

str.match(reg) // [ ‘abbc’, ‘abbbc’, ‘abbbbc’, ‘abbbbbc’ ]

复制代码

纵向

一个正则匹配的字符串,具体到某一位字符时,可以不是某个确定的字符串,可以有多种可能,实现方式是字符组( 其实多选分支|也可以实现 )

let reg = /a[123]b/g

let str = ‘a0b a1b a2b a3b a4b’

str.match(reg) // [ ‘a1b’, ‘a2b’, ‘a3b’ ]

复制代码

字符组


不要被名字给糊弄了,虽然他叫做字符组,但其实只是代表一个字符的可能性

范围表示法

[123456abcdefABCDEF] => [1-6a-fA-F]

复制代码

排除字符组

某位字符可以是任何东西,但是就是不能是xxx, 使用^符号

问题:如何要表示除了某个单词之外的任意东西呢?

[^abc]

复制代码

常见简写形式

\d // 数字

\D // 非数字

\w // [0-9a-zA-Z_]

\W // [^0-9a-zA-Z_]

\s // [\t\v\n\r\f]

\S // [^\t\v\n\r\f]

.

复制代码

量词

量词 & 简写

1. {m,} // 至少出现m次

2. {m} // 出现m次

3. ? // 出现0次或者1次,等价于{0,1}

4. + // 至少出现1次,等价于{1,}

5. * // 出现人一次,等价于{0,}

复制代码

贪婪匹配 VS 惰性匹配

正则本身是贪婪的,会尽可能的多匹配符合模式的字符

let regex = /\d{2,5}/g

let string = ‘123 1234 12345 123456’

// 贪婪匹配

// string.match(regex) // [ 123, 1234, 12345, 12345 ]

// 惰性匹配

let regex2 = /\d{2,5}?/g

// string.match(regex) // [ 12, 12, 34, 12, 34, 12, 34, 56  ]

复制代码

量词后面加一个?,即变成了惰性匹配

贪婪量词        惰性量词

{m,n}            {m,n}?

{m,}             {m,}?

?                       ??

+                       +?

*                   *?

复制代码

多选分支


一个模式可以实现横向和纵向的模糊匹配,而多选分支可以支持多个子模式任选其一,形式是(p1|p2|p3)

let regex = /good|nice/g

let string = ‘good idea, nice try.’

// string.match(regex) // [ ‘good’, ‘nice’ ]

// 注意,用/good|goodbye/去匹配’goodbye’ 匹配到的是good

// 因为分支结构是惰性的,前面的匹配上了,后面的就不再尝试了

复制代码

案例分析


1.匹配id

// 1

let regex = /id=“.*?”/ // 想想为什么要加? 不加的话 连后面的class都会匹配到

let string = ‘

’;

console.log(string.match(regex)[0]);

// 2

let regex = /id=“[^”]*"/

let string = ‘

’;

console.log(string.match(regex)[0]);

复制代码

2.匹配16进制的颜色值

// 要求匹配如下颜色

/*

#ffbbad

#Fc01DF

#FFF

#ffE

*/

let regex = /#([a-fA-F\d]{6}|[a-fA-F\d]{3})/g

let string = “#ffbbad #Fc01DF #FFF #ffE”;

console.log(string.match(regex))

//  [“#ffbbad”, “#Fc01DF”, “#FFF”, “#ffE”]

复制代码

3.匹配24小时制时间

/*

要求匹配

23:59

02:07

*/

// 解析:

// 第一位:可以是0、1、2

// 第二位:当第一位位0或者1的时候,可以是0到9、第一位是2的时候,只可以是0到3

// 第三位:固定是冒号:

// 第四位:可以是0到5

// 第五位:0到9

let regex = /^([01]\d|2[0-3]):[0-5]\d$/

console.log(regex.test(‘23:59’)) // true

console.log(regex.test(‘02:07’))// true

// 衍生题,可以是非0

let regex = /^(0?\d|1\d|2[0-3]):(0?|[1-5])\d/

console.log( regex.test(“23:59”) ) // true

console.log( regex.test(“02:07”) ) // true

console.log( regex.test(“7:09”) ) // true

复制代码

4.匹配日期

/*

要求匹配

yyyy-mm-dd格式的日期

注意月份、和日的匹配

*/

let regex = /\d{4}-(0\d|1[0-2])-(0[1-9]|[12]\d|3[01])/

console.log( regex.test(“2017-06-10”) ) // true

console.log( regex.test(“2017-11-10”) ) // true

复制代码

3. 括号的神奇作用

===========

括号的作用是提供了分组(括号内的正则是一个整体,即提供子表达式),便于我们引用它

分组

如何让量词作用于一个整体?

let reg = /(ab)+/g

let string = ‘ababa abbb ababab’

console.log(string.match(reg)) // [“abab”, “ab”, “ababab”]

复制代码

分支结构

分支结构有点像编程里面或的概念||

/*

匹配

I love JavaScript

I love Regular Expression

*/

let reg = /I love (JavaScript|Regular Expression)/

console.log(reg.test(‘I love JavaScript’)) // true

console.log(reg.test(‘I love Regular Expression’)) // true

复制代码

分组引用


通过括号创建子表达式,可以进行数据提取和强大的替换操作,也可以通过js来引用分组内容

提取数据

/*

提取年月日

2021-08-14

*/

let reg = /(\d{4})-(\d{2})-(\d{2})/

console.log(‘2021-08-14’.match(reg))

//  [“2021-08-14”, “2021”, “08”, “14”, index: 0, input: “2021-08-14”, groups: undefined]

// 第二种解法,通过全局的$1…$9读取 引用的括号数据

let reg = /(\d{4})-(\d{2})-(\d{2})/

let string = ‘2021-08-14’

reg.test(string)

console.log(RegExp.$1) // 2021

console.log(RegExp.$2) // 08

console.log(RegExp.$3) // 14

复制代码

数据替换

/*

将以下格式替换为mm/dd/yyy

2021-08-14

*/

// 第一种解法

let reg = /(\d{4})-(\d{2})-(\d{2})/

let string = ‘2021-08-14’

// 第一种写法

let result1 = string.replace(reg, ‘$2/$3/$1’)

console.log(result1) // 08/14/2021

// 第二种写法

let result2 = string.replace(reg, () => {

return RegExp.$2 + ‘/’ + RegExp.$3 + ‘/’ + RegExp.$1

})

console.log(result2) // 08/14/2021

// 第三种写法

let result3 = string.replace(reg, ($0, $1, $2, $3) => {

return $2 + ‘/’ + $3 + ‘/’ + $1

})

console.log(result3) // 08/14/2021

复制代码

反向引用(很重要)


除了通过js引用分组的内容,也可以通过正则来引用分组内容

/*

写一个正则支持以下三种格式

2016-06-12

2016/06/12

2016.06-12

*/

let regex = /(\d{4})([-/.])\d{2}\2\d{2}/

var string1 = “2017-06-12”;

var string2 = “2017/06/12”;

var string3 = “2017.06.12”;

var string4 = “2016-06/12”;

console.log( regex.test(string1) ); // true

console.log( regex.test(string2) ); // true

console.log( regex.test(string3) ); // true

console.log( regex.test(string4) ); // false

复制代码

注意

  1. 引用不存在的分组会怎样?

  2. 即匹配的就是\1 \2本身

  3. 分组后面有量词会怎样?

  4. 分组后面如果有量词,分组最终(注意是分组,不是说整体)捕获的数据是最后一次的匹配

‘12345’.match(/(\d)+/) // [“12345”, “5”, index: 0, input: “12345”, groups: undefined]

/(\d)+ \1/.test(‘12345 1’) // false

/(\d)+ \1/.test(‘12345 5’) // true

复制代码

非捕获性括号


上面使用的括号都会匹配他们匹配到的数据,以便后续引用,所以也可以称为捕获型分组和捕获型分支。

如果想要括号最原始的功能,但不会引用它,也就是既不会出现在API引用里,也不会出现在正则引用里,可以使用

非捕获性括号(?:p)

// 非捕获型引用

let reg = /(?:ab)+/g

console.log(‘ababa abbb ababab’.match(reg)) // [“abab”, “ab”, “ababab”]

// 注意这里,因为是非捕获型分组,所以使用match方法时,不会出现在数组的1位置了

let reg = /(?:ab)+/

总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

大厂Java架构核心笔记(适合中高级程序员阅读):

alse

复制代码

注意

  1. 引用不存在的分组会怎样?

  2. 即匹配的就是\1 \2本身

  3. 分组后面有量词会怎样?

  4. 分组后面如果有量词,分组最终(注意是分组,不是说整体)捕获的数据是最后一次的匹配

‘12345’.match(/(\d)+/) // [“12345”, “5”, index: 0, input: “12345”, groups: undefined]

/(\d)+ \1/.test(‘12345 1’) // false

/(\d)+ \1/.test(‘12345 5’) // true

复制代码

非捕获性括号


上面使用的括号都会匹配他们匹配到的数据,以便后续引用,所以也可以称为捕获型分组和捕获型分支。

如果想要括号最原始的功能,但不会引用它,也就是既不会出现在API引用里,也不会出现在正则引用里,可以使用

非捕获性括号(?:p)

// 非捕获型引用

let reg = /(?:ab)+/g

console.log(‘ababa abbb ababab’.match(reg)) // [“abab”, “ab”, “ababab”]

// 注意这里,因为是非捕获型分组,所以使用match方法时,不会出现在数组的1位置了

let reg = /(?:ab)+/

总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

大厂Java架构核心笔记(适合中高级程序员阅读):

[外链图片转存中…(img-xcRXNCb4-1714690179839)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录


  1. a-zA-Z\d ↩︎

  2. a-zA-Z\d ↩︎

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值