关于前端:建议收藏25正则面试题详尽解析让你轻松通过正则面试让你少写2000行代码

23次阅读

共计 16176 个字符,预计需要花费 41 分钟才能阅读完成。

前言

数字千分位宰割、手机号 3 -3- 4 格局拼接、trim 函数实现、HTML 本义、获取 url query 参数 … 你是不是也常常在面试和工作中遇到呢?让咱们一起看看,如何用正则将他们一网打尽吧!!!

1. 数字价格千分位宰割

将 123456789 变成 123,456,789

这道题预计大家在面试和工作中也常常遇到,呈现频率比拟高。

正则后果

'123456789'.replace(/(?!^)(?=(\d{3})+$)/g, ',') // 123,456,789

剖析过程

题目意思大略是:

  1. 从后往前 每三个数字 前加一个逗号
  2. 结尾不能加逗号(比方: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})+$)/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

剖析过程

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

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


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

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

3. 手机号 3 -4- 4 宰割扩大

将手机号 18379836654 转化为 183-7983-6654 须要满足以下条件

  1. 123 => 123
  2. 1234 => 123-4
  3. 12345 => 123-45
  4. 123456 => 123-456
  5. 1234567 => 123-4567
  6. 12345678 => 123-4567-8
  7. 123456789 => 123-4567-89
  8. 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)) // 123
console.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)) // 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 种字符

正则后果

let reg = /((?=.*\d)((?=.*[a-z])|(?=.*[A-Z])))|(?=.*[a-z])(?=.*[A-Z])^[a-zA-Z\d]{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

剖析过程

题目由三个条件组成

  1. 明码长度是 6 -12 位
  2. 由数字、小写字符和大写字母组成
  3. 必须至多包含 2 种字符

第一步,写出条件 1 和 2 和正则

let reg = /^[a-zA-Z\d]{6,12}$/

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

let reg = /(?=.*\d)/
// 这个正则的意思是,匹配的是一个地位
// 这个地位须要满足 ` 任意数量的符号,紧跟着是个数字 `,// 留神它最终失去的是个地位而不是其余的货色
// (?=.*\d)常常用来做条件限度

console.log(reg.test('hello')) // false
console.log(reg.test('hello1')) // true
console.log(reg.test('hel2lo')) // true

// 其余类型同理

第三步,写出残缺的正则

必须蕴含两种字符,有上面四种排列组合形式

  1. 数字和小写字母组合
  2. 数字和大写字母组合
  3. 小写字母与大写字母组合
  4. 数字、小写字母、大写字母一起组合(但其实后面三种曾经笼罩了第四种了)
// 示意条件 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')) // 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

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
}

剖析过程

题目中有几个要害信息是

  1. 间断反复的字符
  2. 间断反复的字符数的长度是不限的(如 23、45 是两位、6 是一位)

那什么是间断反复呢?

11 是间断反复、22 也是间断反复、111 当然也是。也就是说某些字符 X 之后肯定也是跟着 X,就叫间断反复。如果很明确晓得 X 是就是 1,那么 /11+/ 也就能够匹配了,但要害是这里的 X 是不明确的,怎么办呢?。

应用 反向援用 的正则常识能够很不便解决这个问题。

第一步,写出示意有一个字符反复的正则

// 这里的 X 可用. 来示意,即所有的字符,并用括号进行援用,紧跟着反向利用 \1,也就是体现了间断反复的意思啦
let repeatRe = /(.)\1/

console.log(repeatRe.test('11')) // true
console.log(repeatRe.test('22')) // true
console.log(repeatRe.test('333')) // true
console.log(repeatRe.test('123')) // true

第二步,写出示意有 n 个字符反复的正则

因为并不确定是要匹配 11 还是 45 45 所以括号内须要用量词 + 来体现 n 个反复字符,而反向援用自身也能够是大于一个的,例如 45 45 45


let repeatRe = /(.+)\1+/

console.log(repeatRe.test('11')) // true
console.log(repeatRe.test('22')) // true
console.log(repeatRe.test('333')) // true
console.log(repeatRe.test('454545')) // true
console.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 本义,本义规定如下,要求将对应字符转换成等值的实体。而反本义则是将本义后的实体转换为对应的字符

字符 本义后的实体
& &amp;
< &lt;
> &gt;
" &quot;
' &#x27;

正则后果


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>
`))

/*
&lt;div&gt;
  &lt;p&gt;hello world&lt;/p&gt;
&lt;/div&gt;

*/

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(`
  &lt;div&gt;
    &lt;p&gt;hello world&lt;/p&gt;
  &lt;/div&gt;
`))

/*
<div>
  <p>hello world</p>
</div>
*/

9. 将字符串驼峰化

如下规定,将对应字符串变成驼峰写法

1. foo Bar => fooBar

2. foo-bar---- => fooBar

3. foo_bar__ => fooBar

正则后果

const camelCase = (string) => {const camelCaseRegex = /[-_\s]+(.)?/g

  return string.replace(camelCaseRegex, (match, char) => {return char ? char.toUpperCase() : ''
  })
}

剖析过程

剖析题目的法则

  1. 每个单词的后面都有 0 个或者多个- 空格 _ 如(Foo--foo__FOO_BAR Bar)
  2. - 空格 _ 前面有可能不跟任何货色 如(__--)
const camelCase = (string) => {// 留神(.)? 这里的? 是为了满足条件 2
  const camelCaseRegex = /[-_\s]+(.)?/g

  return string.replace(camelCaseRegex, (match, char) => {return char ? char.toUpperCase() : ''
  })
}

console.log(camelCase('foo Bar')) // fooBar
console.log(camelCase('foo-bar--')) // fooBar
console.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 World
console.log(capitalize('hello WORLD')) // Hello World

11. 获取网页中所有 img 标签的图片地址

要求必须是在线链接 例如 https://xxx.juejin.com/a.jpghttp://xxx.juejin.com/a.jpg//xxx.juejjin.com/a.jpg

剖析过程

平时写过一些爬虫的同学对匹配 img 标签的 url 肯定不生疏,为了精确抓取小姐姐的图片地址,肯定动用了你各种聪明才智,最初也如愿以偿。

题目中限定了

  1. 图片标签img
  2. 须要是在线链接模式,一些 base64 的图片须要过滤掉

接下来咱们间接看后果,通过可视化的模式看一下这个正则要示意的意思是啥


const matchImgs = (sHtml) => {const imgUrlRegex = /<img[^>]+src="((?:https?:)?\/\/[^"]+)"[^>]*?>/gi
  let matchImgUrls = []
  
  sHtml.replace(imgUrlRegex, (match, $1) => {$1 && matchImgUrls.push($1)
  })

  return matchImgUrls
}

咱们把正则分成几个局部来看

  1. img 标签到 src 之间的局部,只有不是 >,其余的啥都能够
  2. 括号内的局部,也就是咱们要提取的 url 局部,作为一个捕捉分组存在,不便间接获取

    2.1 (?:https?:)? 示意反对协定头为 http: 或者 https:

    2.2 括号里面的?,示意能够没有协定头,即反对 //xxx.juejjin.com/a.jpg 模式的链接

    2.3 接着是两个斜线

    2.4 因为 src=”” 双引号内的局部即为链接,所以[^"]+ 示意除了 ” 其余局部都行

  3. 接着就是 ” 到 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= 前端胖头鱼 所处的地位可能是

  1. 紧跟着问号 ?name= 前端胖头鱼 &sex=boy
  2. 在最初的地位 ?sex=boy&name= 前端胖头鱼
  3. 在 1 和 2 之间 ?sex=boy&name= 前端胖头鱼 &age=100

所以只有解决三个中央根本就能够通过正则来取了

  1. name 后面只能是? 或者 &
  2. value 的值能够除了是 & 认为的任意货色
  3. 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=boy
console.log(getQueryByName('name')) // 前端胖头鱼

// 2. name 在最初
// https://juejin.cn/?sex=boy&name= 前端胖头鱼
console.log(getQueryByName('name')) // 前端胖头鱼


// 2. name 在两头
// https://juejin.cn/?sex=boy&name= 前端胖头鱼 &age=100
console.log(getQueryByName('name')) // 前端胖头鱼

13. 匹配 24 小时制工夫

判断工夫 time 是否合乎 24 小时制 要求能够匹配规定如下

  1. 01:14
  2. 1:14
  3. 1:1
  4. 23:59

正则后果

const check24TimeRegexp = /^(?:(?:0?|1)\d|2[0-3]):(?:0?|[1-5])\d$/

剖析过程

24 小时制的工夫的 别离须要满足

  1. 第一位能够是 012
  2. 第二位

    2.1 当第一位是 01 时,第二位能够是任意数字

    2.2 当第二位是 2 时,第二位只能是 0、1、2、3

  1. 第一位能够是 0、1、2、3、4、5
  2. 第二位能够是任意数字

第一步,先写出合乎 1 和 4 规定的正则

const check24TimeRegexp = /^(?:[01]\d|2[0-3]):[0-5]\d$/

console.log(check24TimeRegexp.test('01:14')) // true
console.log(check24TimeRegexp.test('23:59')) // true
console.log(check24TimeRegexp.test('23:60')) // false

console.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')) // true
console.log(check24TimeRegexp.test('23:59')) // true
console.log(check24TimeRegexp.test('23:60')) // false

console.log(check24TimeRegexp.test('1:14')) // true
console.log(check24TimeRegexp.test('1:1')) // true

14. 匹配日期格局

要求匹配(yyyy-mm-dd、yyyy.mm.dd、yyyy/mm/dd),例如2021-08-222021.08.222021/08/22 能够不思考平平年

正则后果

const checkDateRegexp = /^\d{4}([-\.\/])(?:0[1-9]|1[0-2])\1(?:0[1-9]|[12]\d|3[01])$/

剖析过程

日期格局次要分为三个局部

  1. yyyy 年局部 这部分只有是四个数字就能够\d{4}
  2. mm 月份局部

    2.1 一年只有 12 个月,前 10 个月能够用0\d

    2.2 10 月份及其当前当前 1[0-2]

  3. 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')) // true
console.log(checkDateRegexp.test('2021/08/22')) // true
console.log(checkDateRegexp.test('2021.08.22')) // true
console.log(checkDateRegexp.test('2021.08/22')) // false
console.log(checkDateRegexp.test('2021/08-22')) // false

可视化模式中有一个 Backref #1,也就是反向援用第一个分组也就 ([-\.\/])、这样就保障了宰割符肯定是一样的

15. 匹配 16 进制的色彩值

要求从字符串 string 中匹配相似 #ffbbad#FFF16 进制色彩值

正则后果

const matchColorRegex = /#(?:[\da-zA-Z]{6}|[\da-zA-Z]{3})/g

剖析过程

16 进制的色彩值由以下两局部组成

  1. #
  2. 6 位或 3 位 数字 大小写字母 组成

const matchColorRegex = /#(?:[\da-zA-Z]{6}|[\da-zA-Z]{3})/g
const 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/')) // true
console.log(checkProtocol.test('http://juejin.cn/')) // true
console.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 能够分成以下几个局部

  1. (?:\+?86)?: 手机前缀,括号内通过 ?: 标识非援用分组
  2. 1: 所有的手机号都是以 1 结尾
  3. (a|b|c|…): 2~5 位的各种状况,通过多选分支 | 进行逐个解释
  4. \d{6}: 6 位任意数字

拆解开来后会发现其实也不简单,只是第三局部因为可能性太多了,用了好多多选分支来阐明,只有理分明了手机号规定,每个分组外面的法则也就不难了。

19. 英文单词加前后空格

字母汉字组成的字符串,用正则给英文单词加前后空格。
如:you 说来是 come,去是 go => you 说来是 come,去是 go 例子

解析过程

这里只有理解正则中 \b 地位的概念就能够了,\b的意思是单词的边界, 具体讲有三点规定

  1. \w 和 \W 之间的地位
  2. ^ 与 \w 之间的地位
  3. \w 与 $ 之间的地位

所以:

第一个单词you,合乎规定 2、

第二个单词 come,合乎规定 1、

第三个单词合乎 go,合乎规定 3


const wordRegex = /\b/g

console.log('you 说来是 come,去是 go'.replace(/\b/g, ' ')) // ` you 说来是 come,去是 go `

20. 字符串大小写取反

将字符串大小写取反,例如 hello WORLD => HELLO world

解析过程

这题比拟容易想到的是通过 ASCII 码确定大小写,而后再转成对应的值即可,然而既然是正则的总结,咱们就尝试一下通过正则来实现。

不通过 ASCII 码那如何确定一个字符是否是大写呢?其实只有将他变成了大写字符,再与元字符比拟一下,相等那阐明远字符也是大写的。比方

对于字符串 x = `A` 
    
'A'.toUpperCase()失去的 y 是 A

y === x

那么 x 就是大写字符

所以题目能够这样写


const stringCaseReverseReg = /[a-z]/ig
const 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 下的 文件 夹和文件门路

要求匹配如下门路

  1. C:\Documents\Newsletters\Summer2018.pdf
  2. C:\Documents\Newsletters\
  3. C:\Documents\Newsletters
  4. C:\

正则后果


const windowsPathRegex = /^[a-zA-Z]:\\(?:[^\\:*<>|"?\r\n/]+\\?)*(?:(?:[^\\:*<>|"?\r\n/]+)\.\w+)?$/;

解析过程

windows 下的文件规定大略由这几局部形成

磁盘符:\ 文件夹 \ 文件夹 \ 文件

  1. 磁盘符:只能是英文形成 [a-zA_Z]:\\
  2. 文件夹名字:不蕴含一些特殊符号且可呈现任意次, 最初的 \ 能够没有 ([^\\:*<>|"?\r\n/]+\\?)*
  3. 文件名字:([^\\:*<>|"?\r\n/]+)\.\w+,然而文件能够没有
const windowsPathRegex = /^[a-zA-Z]:\\(?:[^\\:*<>|"?\r\n/]+\\?)*(?:(?:[^\\:*<>|"?\r\n/]+)\.\w+)?$/;

console.log(windowsPathRegex.test("C:\\Documents\\Newsletters\\Summer2018.pdf") ); // true
console.log(windowsPathRegex.test("C:\\Documents\Newsletters\\") ); // true
console.log(windowsPathRegex.test("C:\\Documents\Newsletters") ); // true
console.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="([^"]+)"/g

document.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)$/

剖析过程

咱们能够将这道题分成两局部看

  1. 整数局部

    1. 个位整数
    2. 十位整数
    3. 百位整数但小于 150
  2. 小数局部:只能是.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)) // true
console.log(pointRegex.test(10)) // true
console.log(pointRegex.test(100)) // true
console.log(pointRegex.test(110.5)) // false
console.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.z
const 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'))

相约再见

用好正则,还有很长的一段路要走,心愿这些解析对大家有帮忙呢!如果文章有任何谬误,或者您有更好的正则写法,欢送提出噢。

正文完
 0