前言
数字千分位宰割、手机号3-3-4格局拼接、trim函数实现、HTML本义、获取url query参数...你是不是也常常在面试和工作中遇到呢?让咱们一起看看,如何用正则将他们一网打尽吧!!!
1. 数字价格千分位宰割
将123456789变成123,456,789
这道题预计大家在面试和工作中也常常遇到,呈现频率比拟高。
正则后果
'123456789'.replace(/(?!^)(?=(\d{3})+$)/g, ',') // 123,456,789
剖析过程
题目意思大略是:
- 从后往前
每三个数字
前加一个逗号 - 结尾不能加逗号(比方:
123
最初不能变成,123
)
是不是很合乎(?=p)的法则呢?p能够示意每三个数字,要增加的逗号所处的地位正好是(?=p)匹配进去的地位。
第一步,尝试先把前面第一个逗号弄出来
let price = '123456789'let priceReg = /(?=\d{3}$)/console.log(price.replace(proceReg, ',')) // 123456,789
第二步,把所有的逗号都弄出来
要把所有的逗号都弄出来,次要要解决的问题是怎么示意三个数字一组
,也就是3的倍数。咱们晓得正则中括号能够把一个p模式变成一个小整体,所以利用括号的个性,能够这样写
let price = '123456789'let priceReg = /(?=(\d{3})+$)/gconsole.log(price.replace(priceReg, ',')) // ,123,456,789
第三步,去掉首位的逗号,
下面曾经基本上实现需求了,然而还不够,首位还会呈现逗号,那怎么把首位的逗号去除呢?想想是不是有一个常识正好满足这个场景? 没错(?!p),就是他了,两者联合就是从后往前每三个数字的地位前增加逗号,然而这个地位不能是^首位。
let price = '123456789'let priceReg = /(?!^)(?=(\d{3})+$)/gconsole.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
剖析过程
有了下面数字的千分位宰割法,做这个题置信会简略很多,也就是从后往前找到这样的地位:
每四个数字前的地位,并把这个地位替换为-
let mobile = '18379836654'let mobileReg = /(?=(\d{4})+$)/gconsole.log(mobile.replace(mobileReg, '-')) // 183-7983-6654
3. 手机号3-4-4宰割扩大
将手机号18379836654转化为183-7983-6654 须要满足以下条件
- 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
想想这其实是咱们常常遇到的用户输出手机号的过程中,须要一直格式化。
正则后果
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(18379836654))
剖析过程
这里用(?=p)就不太适合了,例如1234就会变成-1234。咱们须要另寻他法,
正则中还有其余的知识点不便解决这种场景吗?有 (?<=p)
第一步, 将第一个-弄出来
const formatMobile = (mobile) => { return String(mobile).replace(/(?<=\d{3})\d+/, '-') }console.log(formatMobile(123)) // 123console.log(formatMobile(1234)) // 123-4
将第二个-弄出来
接着咱们弄出来第二个,第二个-正好处于第8位(1234567-)的地位。
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)) // 123console.log(formatMobile(1234)) // 123-4console.log(formatMobile(12345)) // 123-45console.log(formatMobile(123456)) // 123-456console.log(formatMobile(1234567)) // 123-4567console.log(formatMobile(12345678)) // 123-4567-8console.log(formatMobile(123456789)) // 123-4567-89console.log(formatMobile(12345678911)) // 123-4567-8911
4。 验证明码的合法性
明码长度是6-12位,由数字、小写字母和大写字母组成,但必须至多包含2种字符
正则后果
let reg = /((?=.*\d)((?=.*[a-z])|(?=.*[A-Z])))|(?=.*[a-z])(?=.*[A-Z])^[a-zA-Z\d]{6,12}$/console.log(reg.test('123456')) // falseconsole.log(reg.test('aaaaaa')) // falseconsole.log(reg.test('AAAAAAA')) // falseconsole.log(reg.test('1a1a1a')) // trueconsole.log(reg.test('1A1A1A')) // trueconsole.log(reg.test('aAaAaA')) // trueconsole.log(reg.test('1aA1aA1aA')) // true
剖析过程
题目由三个条件组成
- 明码长度是6-12位
- 由数字、小写字符和大写字母组成
- 必须至多包含2种字符
第一步,写出条件1和2和正则
let reg = /^[a-zA-Z\d]{6,12}$/
第二步,必须蕴含某种字符(数字、小写字母、大写字母)
let reg = /(?=.*\d)/// 这个正则的意思是,匹配的是一个地位// 这个地位须要满足`任意数量的符号,紧跟着是个数字`,// 留神它最终失去的是个地位而不是其余的货色// (?=.*\d)常常用来做条件限度console.log(reg.test('hello')) // falseconsole.log(reg.test('hello1')) // trueconsole.log(reg.test('hel2lo')) // true// 其余类型同理
第三步,写出残缺的正则
必须蕴含两种字符,有上面四种排列组合形式
- 数字和小写字母组合
- 数字和大写字母组合
- 小写字母与大写字母组合
- 数字、小写字母、大写字母一起组合(但其实后面三种曾经笼罩了第四种了)
// 示意条件1和2// let reg = /((?=.*\d)((?=.*[a-z])|(?=.*[A-Z])))/// 示意条件条件3// let reg = /(?=.*[a-z])(?=.*[A-Z])/// 示意条件123// let reg = /((?=.*\d)((?=.*[a-z])|(?=.*[A-Z])))|(?=.*[a-z])(?=.*[A-Z])/// 示意题目所有条件let reg = /((?=.*\d)((?=.*[a-z])|(?=.*[A-Z])))|(?=.*[a-z])(?=.*[A-Z])^[a-zA-Z\d]{6,12}$/console.log(reg.test('123456')) // falseconsole.log(reg.test('aaaaaa')) // falseconsole.log(reg.test('AAAAAAA')) // falseconsole.log(reg.test('1a1a1a')) // trueconsole.log(reg.test('1A1A1A')) // trueconsole.log(reg.test('aAaAaA')) // trueconsole.log(reg.test('1aA1aA1aA')) // true
5. 提取间断反复的字符
将有反复的字符提取进去,例如12323454545666,提取[ '23', '45', '6' ]
正则后果
const collectRepeatStr = (str) => { let repeatStrs = [] const repeatRe = /(.+)\1+/g str.replace(repeatRe, ($0, $1) => { $1 && repeatStrs.push($1) }) return repeatStrs}
剖析过程
题目中有几个要害信息是
- 间断反复的字符
- 间断反复的字符数的长度是不限的(如23、45是两位、6是一位)
那什么是间断反复呢?
11是间断反复、22也是间断反复、111当然也是。也就是说某些字符X之后肯定也是跟着X,就叫间断反复。如果很明确晓得X是就是1,那么/11+/
也就能够匹配了,但要害是这里的X是不明确的,怎么办呢?。
应用反向援用
的正则常识能够很不便解决这个问题。
第一步,写出示意有一个字符反复的正则
// 这里的X可用.来示意,即所有的字符,并用括号进行援用,紧跟着反向利用\1,也就是体现了间断反复的意思啦let repeatRe = /(.)\1/console.log(repeatRe.test('11')) // trueconsole.log(repeatRe.test('22')) // trueconsole.log(repeatRe.test('333')) // trueconsole.log(repeatRe.test('123')) // true
第二步,写出示意有n个字符反复的正则
因为并不确定是要匹配11还是45
45
所以括号内须要用量词+来体现n个反复字符,而反向援用自身也能够是大于一个的,例如 45
45
45
let repeatRe = /(.+)\1+/console.log(repeatRe.test('11')) // trueconsole.log(repeatRe.test('22')) // trueconsole.log(repeatRe.test('333')) // trueconsole.log(repeatRe.test('454545')) // trueconsole.log(repeatRe.test('124')) // false
第三步,提取所有间断反复的字符
const collectRepeatStr = (str) => { let repeatStrs = [] const repeatRe = /(.+)\1+/g // 很多时候replace并不是用来做替换,而是做数据提取用 str.replace(repeatRe, ($0, $1) => { $1 && repeatStrs.push($1) }) return repeatStrs}console.log(collectRepeatStr('11')) // ["1"]console.log(collectRepeatStr('12323')) // ["23"]console.log(collectRepeatStr('12323454545666')) // ["23", "45", "6"]
6. 实现一个trim函数
去除字符串的首尾空格
正则后果
// 去除空格法const trim = (str) => { return str.replace(/^\s*|\s*$/g, '') }// 提取非空格法const trim = (str) => { return str.replace(/^\s*(.*?)\s*$/g, '$1') }
剖析过程
初看题目咱们脑海中闪过的做法是把空格局部删除掉,保留非空格的局部
,然而也能够换一种思路,也能够把非空格的局部提取进去,不论空格的局部。接下来咱们来写一下两种trim办法的实现
形式一、去除空格法
const trim = (str) => { return str.replace(/^\s*|\s*$/g, '') }console.log(trim(' 前端胖头鱼')) // 前端胖头鱼console.log(trim('前端胖头鱼 ')) // 前端胖头鱼 console.log(trim(' 前端胖头鱼 ')) // 前端胖头鱼console.log(trim(' 前端 胖头鱼 ')) // 前端 胖头鱼
形式二、提取非空格法
const trim = (str) => { return str.replace(/^\s*(.*?)\s*$/g, '$1') }console.log(trim(' 前端胖头鱼')) // 前端胖头鱼console.log(trim('前端胖头鱼 ')) // 前端胖头鱼 console.log(trim(' 前端胖头鱼 ')) // 前端胖头鱼console.log(trim(' 前端 胖头鱼 ')) // 前端 胖头鱼
7. HTML本义
避免XSS攻打的形式之一就是做HTML本义,本义规定如下,要求将对应字符转换成等值的实体。而反本义则是将本义后的实体转换为对应的字符
字符 | 本义后的实体 | |
---|---|---|
& | & | |
< | < | |
> | > | |
" | " | |
' | ' |
正则后果
const escape = (string) => { const escapeMaps = { '&': 'amp', '<': 'lt', '>': 'gt', '"': 'quot', "'": '#39' } const escapeRegexp = new RegExp(`[${Object.keys(escapeMaps).join('')}]`, 'g') return string.replace(escapeRegexp, (match) => `&${escapeMaps[match]};`)}
剖析过程
全局匹配&
、<
、>
、"
、'
,将其依照上述表格替换就能够。相似这种某个字符可能是多种状况之一的时候,咱们个别会应用字符组
来做 即[&<>"']
const escape = (string) => { const escapeMaps = { '&': 'amp', '<': 'lt', '>': 'gt', '"': 'quot', "'": '#39' } // 这里和/[&<>"']/g的成果是一样的 const escapeRegexp = new RegExp(`[${Object.keys(escapeMaps).join('')}]`, 'g') return string.replace(escapeRegexp, (match) => `&${escapeMaps[match]};`)}console.log(escape(` <div> <p>hello world</p> </div>`))/*<div> <p>hello world</p></div>*/
8. HTML反本义
正则后果
反本义也就是方才的逆过程,咱们很容易写出
const unescape = (string) => { const unescapeMaps = { 'amp': '&', 'lt': '<', 'gt': '>', 'quot': '"', '#39': "'" } const unescapeRegexp = /&([^;]+);/g return string.replace(unescapeRegexp, (match, unescapeKey) => { return unescapeMaps[ unescapeKey ] || match })}console.log(unescape(` <div> <p>hello world</p> </div>`))/*<div> <p>hello world</p></div>*/
9. 将字符串驼峰化
如下规定,将对应字符串变成驼峰写法
1. foo Bar => fooBar2. foo-bar---- => fooBar3. foo_bar__ => fooBar
正则后果
const camelCase = (string) => { const camelCaseRegex = /[-_\s]+(.)?/g return string.replace(camelCaseRegex, (match, char) => { return char ? char.toUpperCase() : '' })}
剖析过程
剖析题目的法则
- 每个单词的后面都有0个或者多个
-
空格
_
如(Foo
、--foo
、__FOO
、_BAR
、Bar
) -
空格
_
前面有可能不跟任何货色 如(__
、--
)
const camelCase = (string) => { // 留神(.)?这里的?是为了满足条件2 const camelCaseRegex = /[-_\s]+(.)?/g return string.replace(camelCaseRegex, (match, char) => { return char ? char.toUpperCase() : '' })}console.log(camelCase('foo Bar')) // fooBarconsole.log(camelCase('foo-bar--')) // fooBarconsole.log(camelCase('foo_bar__')) // fooBar
10. 将字符串首字母转化为大写,剩下为小写
例如 hello world 转为为Hello World
正则后果
const capitalize = (string) => { const capitalizeRegex = /(?:^|\s+)\w/g return string.toLowerCase().replace(capitalizeRegex, (match) => match.toUpperCase())}
剖析过程
找到单词的首字母而后将其转化为大写字母就能够,单词后面可能是结尾
也可能是多个空格
。
const capitalize = (string) => { const capitalizeRegex = /(?:^|\s+)\w/g return string.toLowerCase().replace(capitalizeRegex, (match) => match.toUpperCase())}console.log(capitalize('hello world')) // Hello Worldconsole.log(capitalize('hello WORLD')) // Hello World
11. 获取网页中所有img标签的图片地址
要求必须是在线链接 例如https://xxx.juejin.com/a.jpg
、http://xxx.juejin.com/a.jpg
、//xxx.juejjin.com/a.jpg
剖析过程
平时写过一些爬虫的同学对匹配img标签的url肯定不生疏,为了精确抓取小姐姐的图片地址,肯定动用了你各种聪明才智,最初也如愿以偿。
题目中限定了
- 图片标签
img
- 须要是在线链接模式,一些base64的图片须要过滤掉
接下来咱们间接看后果,通过可视化的模式看一下这个正则要示意的意思是啥
const matchImgs = (sHtml) => { const imgUrlRegex = /<img[^>]+src="((?:https?:)?\/\/[^"]+)"[^>]*?>/gi let matchImgUrls = [] sHtml.replace(imgUrlRegex, (match, $1) => { $1 && matchImgUrls.push($1) }) return matchImgUrls}
咱们把正则分成几个局部来看
- img标签到src之间的局部,只有不是>,其余的啥都能够
括号内的局部,也就是咱们要提取的url局部,作为一个捕捉分组存在,不便间接获取
2.1 (?:https?:)? 示意反对协定头为http:或者https:
2.2 括号里面的?,示意能够没有协定头,即反对
//xxx.juejjin.com/a.jpg
模式的链接2.3 接着是两个斜线
2.4 因为src="" 双引号内的局部即为链接,所以
[^"]+
示意除了"其余局部都行- 接着就是"到img完结标签>之间的局部了,除了>之外,啥都能够
[^>]*?
试试后果
咱们到知乎,关上控制台,能够看到是合乎预期的。
12.通过name获取url query参数
正则后果
const getQueryByName = (name) => { const queryNameRegex = new RegExp(`[?&]${name}=([^&]*)(&|$)`) const queryNameMatch = window.location.search.match(queryNameRegex) // 个别都会通过decodeURIComponent解码解决 return queryNameMatch ? decodeURIComponent(queryNameMatch[1]) : ''}
剖析过程
url query上的参数 name=前端胖头鱼
所处的地位可能是
紧跟着问号
?name=前端胖头鱼&sex=boy在最初的地位
?sex=boy&name=前端胖头鱼在1和2之间
?sex=boy&name=前端胖头鱼&age=100
所以只有解决三个中央根本就能够通过正则来取了
- name后面只能是?或者&
- value的值能够除了是&认为的任意货色
- value前面只能是跟着&或者是完结地位
const getQueryByName = (name) => { const queryNameRegex = new RegExp(`[?&]${name}=([^&]*)(?:&|$)`) const queryNameMatch = window.location.search.match(queryNameRegex) // 个别都会通过decodeURIComponent解码解决 return queryNameMatch ? decodeURIComponent(queryNameMatch[1]) : ''}// 1. name在最后面// https://juejin.cn/?name=前端胖头鱼&sex=boyconsole.log(getQueryByName('name')) // 前端胖头鱼// 2. name在最初// https://juejin.cn/?sex=boy&name=前端胖头鱼console.log(getQueryByName('name')) // 前端胖头鱼// 2. name在两头// https://juejin.cn/?sex=boy&name=前端胖头鱼&age=100console.log(getQueryByName('name')) // 前端胖头鱼
13. 匹配24小时制工夫
判断工夫time是否合乎24小时制 要求能够匹配规定如下
01:14
1:14
1:1
23:59
正则后果
const check24TimeRegexp = /^(?:(?:0?|1)\d|2[0-3]):(?:0?|[1-5])\d$/
剖析过程
24小时制的工夫的时
和分
别离须要满足
时
- 第一位能够是012
第二位
2.1 当第一位是01时,第二位能够是任意数字
2.2 当第二位是2时,第二位只能是0、1、2、3
分
- 第一位能够是0、1、2、3、4、5
- 第二位能够是任意数字
第一步,先写出合乎1和4规定的正则
const check24TimeRegexp = /^(?:[01]\d|2[0-3]):[0-5]\d$/console.log(check24TimeRegexp.test('01:14')) // trueconsole.log(check24TimeRegexp.test('23:59')) // trueconsole.log(check24TimeRegexp.test('23:60')) // falseconsole.log(check24TimeRegexp.test('1:14')) // false 理论须要反对console.log(check24TimeRegexp.test('1:1')) // false 理论须要反对
第二步,写出时和分都能够是复数的状况
const check24TimeRegexp = /^(?:(?:0?|1)\d|2[0-3]):(?:0?|[1-5])\d$/console.log(check24TimeRegexp.test('01:14')) // trueconsole.log(check24TimeRegexp.test('23:59')) // trueconsole.log(check24TimeRegexp.test('23:60')) // falseconsole.log(check24TimeRegexp.test('1:14')) // trueconsole.log(check24TimeRegexp.test('1:1')) // true
14. 匹配日期格局
要求匹配(yyyy-mm-dd、yyyy.mm.dd、yyyy/mm/dd),例如2021-08-22
、2021.08.22
、2021/08/22
能够不思考平平年
正则后果
const checkDateRegexp = /^\d{4}([-\.\/])(?:0[1-9]|1[0-2])\1(?:0[1-9]|[12]\d|3[01])$/
剖析过程
日期格局次要分为三个局部
yyyy年局部
这部分只有是四个数字就能够\d{4}
mm月份局部
2.1 一年只有12个月,前10个月能够用
0\d
2.2 10月份及其当前当前
1[0-2]
dd日局部
3.1 一个月最多是31日
3.2 最小是1号
分隔符
须要留神的是宰割符必须一样不能-./三种混用,比方2021.08-22
依据以上剖析咱们能够写出
const checkDateRegexp = /^\d{4}([-\.\/])(?:0[1-9]|1[0-2])\1(?:0[1-9]|[12]\d|3[01])$/console.log(checkDateRegexp.test('2021-08-22')) // trueconsole.log(checkDateRegexp.test('2021/08/22')) // trueconsole.log(checkDateRegexp.test('2021.08.22')) // trueconsole.log(checkDateRegexp.test('2021.08/22')) // falseconsole.log(checkDateRegexp.test('2021/08-22')) // false
可视化模式中有一个Backref #1 ,也就是反向援用第一个分组也就 ([-\.\/])
、这样就保障了宰割符肯定是一样的
15. 匹配16进制的色彩值
要求从字符串string中匹配相似#ffbbad
、#FFF
16进制色彩值
正则后果
const matchColorRegex = /#(?:[\da-zA-Z]{6}|[\da-zA-Z]{3})/g
剖析过程
16进制的色彩值由以下两局部组成
#
- 6位或3位
数字
、大小写字母
组成
const matchColorRegex = /#(?:[\da-zA-Z]{6}|[\da-zA-Z]{3})/gconst colorString = '#12f3a1 #ffBabd #FFF #123 #586'console.log(colorString.match(matchColorRegex))// [ '#12f3a1', '#ffBabd', '#FFF', '#123', '#586' ]
咱们不能把正则写成/#(?:[\da-zA-Z]{3}|[\da-zA-Z]{6})/g
,因为正则中的多选分支|是惰性匹配的,优先匹配后面的分支,这时候去匹配'#12f3a1 #ffBabd #FFF #123 #586'
,将会失去[ '#12f', '#ffB', '#FFF', '#123', '#586' ]
16. 检测URL前缀
查看一个url是否是http或者https协定头
这个绝对简略,然而在日常工作中还是常常碰到。
正则后果
const checkProtocol = /^https?:/console.log(checkProtocol.test('https://juejin.cn/')) // trueconsole.log(checkProtocol.test('http://juejin.cn/')) // trueconsole.log(checkProtocol.test('//juejin.cn/')) // false
17. 检测中文
检测字符串str是否是都由中文组成
最重要是要确定中文在unicode的编码范畴汉字 Unicode 编码范畴,如果要加上根本汉字之外的匹配,只须要用多选分支即可
剖析过程
const checkChineseRegex = /^[\u4E00-\u9FA5]+$/console.log(checkChineseRegex.test('前端胖头鱼'))console.log(checkChineseRegex.test('1前端胖头鱼'))console.log(checkChineseRegex.test('前端胖头鱼2'))
18. 匹配手机号
检测一个字符串是否合乎手机号的规定
时效性
手机号自身是有时效性的,各大运营商有时候会推出新的号码,所以咱们的正则也具备时效性,须要及时补充
规律性
具体法则能够查看 中国大陆挪动终端通信号码
解析过程
正则参考自 ChinaMobilePhoneNumberRegex
const mobileRegex = /^(?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[235-8]\d{2}|4(?:0\d|1[0-2]|9\d))|9[0-35-9]\d{2}|66\d{2})\d{6}$/console.log(mobileRegex.test('18379867725'))console.log(mobileRegex.test('123456789101'))console.log(mobileRegex.test('+8618379867725'))console.log(mobileRegex.test('8618379867725'))
当遇到一个很长看起来很简单的正则的时候,有什么好方法能够让咱们看懂它?
能够借助可视化工具辅助咱们拆解正则。
所以mobileRegex能够分成以下几个局部
(?:\+?86)?
: 手机前缀,括号内通过?:
标识非援用分组- 1: 所有的手机号都是以1结尾
- (a|b|c|...): 2~5位的各种状况,通过多选分支|进行逐个解释
- \d{6}: 6位任意数字
拆解开来后会发现其实也不简单,只是第三局部因为可能性太多了,用了好多多选分支来阐明,只有理分明了手机号规定,每个分组外面的法则也就不难了。
19. 英文单词加前后空格
字母汉字组成的字符串,用正则给英文单词加前后空格。
如:you说来是come,去是go
=>you 说来是 come ,去是 go
例子
解析过程
这里只有理解正则中\b
地位的概念就能够了,\b
的意思是单词的边界,具体讲有三点规定
- \w和\W之间的地位
- ^与\w之间的地位
- \w与$之间的地位
所以:
第一个单词you
,合乎规定2、
第二个单词come,合乎规定1、
第三个单词合乎go,合乎规定3
const wordRegex = /\b/gconsole.log('you说来是come,去是go'.replace(/\b/g, ' ')) // ` you 说来是 come ,去是 go `
20. 字符串大小写取反
将字符串大小写取反,例如hello WORLD => HELLO world
解析过程
这题比拟容易想到的是通过ASCII码确定大小写,而后再转成对应的值即可,然而既然是正则的总结,咱们就尝试一下通过正则来实现。
不通过ASCII码那如何确定一个字符是否是大写呢?其实只有将他变成了大写字符,再与元字符比拟一下,相等那阐明远字符也是大写的。比方
对于字符串 x = `A` 'A'.toUpperCase()失去的y是Ay === x那么x就是大写字符
所以题目能够这样写
const stringCaseReverseReg = /[a-z]/igconst string = 'hello WORLD'const string2 = string.replace(stringCaseReverseReg, (char) => { const upperStr = char.toUpperCase() // 大写转小写,小写转大写 return upperStr === char ? char.toLowerCase() : upperStr})console.log(string2) // HELLO world
21. windows下的文件
夹和文件门路
要求匹配如下门路
- C:\Documents\Newsletters\Summer2018.pdf
- C:\Documents\Newsletters\
- C:\Documents\Newsletters
- C:\
正则后果
const windowsPathRegex = /^[a-zA-Z]:\\(?:[^\\:*<>|"?\r\n/]+\\?)*(?:(?:[^\\:*<>|"?\r\n/]+)\.\w+)?$/;
解析过程
windows下的文件规定大略由这几局部形成
磁盘符:\文件夹\文件夹\文件
- 磁盘符:只能是英文形成
[a-zA_Z]:\\
- 文件夹名字:不蕴含一些特殊符号且可呈现任意次,最初的\能够没有
([^\\:*<>|"?\r\n/]+\\?)*
- 文件名字:
([^\\:*<>|"?\r\n/]+)\.\w+
,然而文件能够没有
const windowsPathRegex = /^[a-zA-Z]:\\(?:[^\\:*<>|"?\r\n/]+\\?)*(?:(?:[^\\:*<>|"?\r\n/]+)\.\w+)?$/;console.log( windowsPathRegex.test("C:\\Documents\\Newsletters\\Summer2018.pdf") ); // trueconsole.log( windowsPathRegex.test("C:\\Documents\Newsletters\\") ); // trueconsole.log( windowsPathRegex.test("C:\\Documents\Newsletters") ); // trueconsole.log( windowsPathRegex.test("C:\\") ); // true
22. 匹配id(写爬虫获取html常常用到)
要求<div id="box">hello world</div>
中的id box
正则后果
const matchIdRegexp = /id="([^"]*)"/console.log(` <div id="box"> hello world </div>`.match(matchIdRegexp)[1])
解析过程
写爬虫的过程中常常须要匹配指定条件的dom元素,而后再去做对应的操作。那么怎么获取box呢
<div id="box"> hello world</div>
置信大家最先想到的是这个正则id="(.*)"
const matchIdRegexp = /id="(.*)"/console.log(` <div id="box"> hello world </div>`.match(matchIdRegexp)[1])
然而id="(.*)"
很容易导致回溯,从而消耗更多的匹配工夫。有什么优化的形式吗?
是的只须要将.
换成[^"]
即可,当遇到"时,正则即认为匹配完结,也就不会产生回溯了。
const matchIdRegexp = /id="([^"]*)"/console.log(` <div id="box"> hello world </div>`.match(matchIdRegexp)[1])
23. 匹配id 扩大(获取掘金首页html所有id)
咱们试试能不能批量获取id
正则后果
const idRegexp = /id="([^"]+)"/gdocument.body.innerHTML .match(idRegexp) .map((idStr) => idStr.replace(idRegexp, '$1'))
24. 大于等于0, 小于等于150, 反对小数位呈现5, 如145.5, 用于判断考卷分数
正则后果
const pointRegex = /^(?:[1-9]?\d|1[0-4]\d)$/
剖析过程
咱们能够将这道题分成两局部看
整数局部
- 个位整数
- 十位整数
- 百位整数但小于150
- 小数局部:只能是
.5
或者没有
先尝试写整数局部
// 1. 如何示意个位数? /\d/// 2. 如何示意十位数? /[1-9]\d/// 3. 个位和十位如何一起示意? /[1-9]?\d/// 4. 小于150的百位数呢? /1[0-4]\d/// 所以联合起来整数局部能够用以下正则示意const pointRegex = /^(?:[1-9]?\d|1[0-4]\d)$/console.log(pointRegex.test(0)) // trueconsole.log(pointRegex.test(10)) // trueconsole.log(pointRegex.test(100)) // trueconsole.log(pointRegex.test(110.5)) // falseconsole.log(pointRegex.test(150)) // false
再加上小数局部
// 小数局部绝对简略 /(?:\.5)?/,所以整体联合起来就是const pointRegex = /^(?:[1-9]?\d|1[0-4]\d)(?:\.5)?$/console.log(pointRegex.test(0))console.log(pointRegex.test(10))console.log(pointRegex.test(100))console.log(pointRegex.test(110.5))console.log(pointRegex.test(150))
25. 判断版本号
要求版本号必须是X.Y.Z格局,其中XYZ都是至多一位的数字
正则后果
// x.y.zconst versionRegexp = /^(?:\d+\.){2}\d+$/console.log(versionRegexp.test('1.1.1'))console.log(versionRegexp.test('1.000.1'))console.log(versionRegexp.test('1.000.1.1'))
相约再见
用好正则,还有很长的一段路要走,心愿这些解析对大家有帮忙呢!如果文章有任何谬误,或者您有更好的正则写法,欢送提出噢。