正则表达式-做几个题

## 将get-element-by-id转化成驼峰

想要转化成驼峰,首先查看共同点,很明显,这个字符串的共同点就是-e,-b,-i,那么如何匹配呢?

### 范围匹配

  • []表示范围匹配,比如需要匹配数字,那么可以写作[0-9],等价于\d
  • 如果要匹配非数字,那么就是[^0-9],等价于\D

### \w

  • \w用于匹配单词字符,包含0-9,a-z,A-z以及下划线_,等价于[A-Za-z0-9_]

### g

  • 标志g表示全局匹配,匹配到第一个字符之后,会继续匹配,直到没有符合规则的字符为止。

    1
    2
    3
    4
    5
      // replace 第二个参数如果是函数,返回值将替换掉匹配到的结果
      'get-element-by-id'.replace(/-\w/g, (match) => {
        // 我们用第二个字母的大写字母,替换掉 ’-i‘
        return match[1].toUpperCase()
      })
    

    当然,用/-[a-z]/也行,只不过当字符串变成get-Element-by-id之后,返回值会变成get-ElementById

## 匹配二进制数字

什么是二进制?1开头,后续为任意1或0。so

### ^

  • 匹配字符开始。比如以数字开头/^\d/

### $

  • 匹配字符的结束。

### *

  • 匹配前面的子表达式零次或任意次

### +

  • 匹配前面的子表达式一次或多次
1
2
3
4
    const reg = /^1[10]*$/
    reg.test('101030') // false
    reg.test('101011110') // true
    reg.test('001011110') // false

## 非0的十进制数字,不能以0开头,至少一位数字 首先匹配数字,很简单/^\d+$/,主要解决的是第一位不能是0。so?/^[1-9]\d*$/

## 匹配一年中的12个月 第一眼望过去,没懂题目意思,姑且认为是匹配01,02….12。一顿猛如虎分析:0开头,后面跟1-9,或者1开头,后面跟1、2。

### 或 |

  • 就是正则的或逻辑,要注意的是,|隔断的是其左右的整个子表达式,而不是单个普通字符。

so 结果就是/^(0[1-9]|1[0-2])$/,但是,要是1-9月份就是1,2,3….9,那是不是直接/[1-12]/,哈哈,开个玩笑。就是说0可以不要可以要,那该怎么做呢?

### ?

  • 匹配前面的子表达式零次或一次

看到这个?,应该就很容易实现了,0要不要都可以,/^(0?[1-9]|1[0-2])$/

## 匹配qq号最长为13位 这个问题大概是,任意1-13位的数字?好像不对,听说QQ号最少5位,并且也不能用0开头。

### {n,m}

  • 匹配前一个普通字符或者子表达式最少n次,最多m次

### {n,}

  • 匹配前一个普通字符或者子表达式最少n次

### {n}

  • 匹配前一个普通字符或者子表达式n次

/^[1-9][0-9]{4,12}$/

## 匹配常见的固定电话号码 固定号码的规则:区号0开头,后面2-3位,加上-,然后加上7-8位固定电话号码。 /^0\d{2,3}-\d{7,8}/

## 匹配手机号码 手机号码规则:1开头,后面10位数字 /^1\d{10}$/ 稍微严格点的规则:1开头,第二位为3-9,然后加9位数字 /^1[3-9]\d{9}$/ 更严格的规则:个人认为没必要,要是按照目前的规则具体到每一位,一旦出现新规则还得重新改,得不偿失

## 匹配ip地址

  • IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
  • IP地址的长度为32位(共有2^32个IP地址),分为4段,每段8位,用十进制数字表示,每段数字范围为0~255,段与段之间用句点隔开。

所以匹配ip主要就是匹配0-255,/[01]?\d{1,2}/这个表达式可以匹配1-199, 包含了000-199,接下来是200-255,这里主要需要注意的是,当第二位是5的时候,第三位最大只能是5,第二位最大是5,/2\d{2}/这是200-299,/2[0-5]\d/这是200-259,/2([0-4]\d|5[0-5])/这是200-255,连起来就是/([01]?\d{1,2})|(2([0-4]\d)|(5[0-5]))/,所以完整的就是3个‘255.’加上‘255’

1
2
3
4
5
6
7
    var reg = /^(([01]?\d{1,2}|2([0-4]\d|5[0-5]))\.){3}([01]?\d{1,2}|2([0-4]\d|5[0-5]))$/g
    var ip = '255.255.255.12'
    var ip2 = '255.255.255.1244'
    console.log(reg.test(ip)) // true
    console.log(ip.match(reg)) // ["255.255.255.12"]
    console.log(reg.test(ip2)) // false
    console.log(ip.match(reg2)) // null

## 匹配用尖括号括起来的以a开头的字符串 这个题是<a开头>结尾,中间可以是任意字符串,当然不能出现>,一旦出现就结尾了 /^<a[^>]*>$/

## 千位分隔符 看一组数字123456789,我们需要的结果是123,456,789,继续找规律,千分位分隔符就是从右开始,每3位加一个,,需要注意的一点是,正则是从头部开始匹配的,首先就是数字3位,\d{3},匹配到3位数字之后,往前面加上,,但是3位数字的前面必须得有一个数字,不然不能加,所以我们的目标是找到3位数字前面的那一个数字,把它替换成\d,

### 非捕获组(?:)

  • 非捕获组是不生成引用的分组,它也由圆括号()包裹起来,不过圆括号中起头的是?:,也就是/(?:\d*)/这种形式。

看到非捕获组这个规则,很容易想到,当我们把‘3位数字’匹配成非捕获组,那么我们匹配到的‘数字+3位数字’就可以直接替换成‘数字+,’,因为’3位数字‘不会被捕获到。

### 零宽正向先行断言(?=)

  • 约束目标右侧必须存在指定的字符。

正因为正则是从左往右匹配的,所以‘一个数字’的后面必须是’3个数字‘这样的1-无数个组合,所以我们用到了零宽正向先行断言(?=)

### replace

  • replace()是字符串替换方法,它不要求第一个参数必须是正则表达式。如果第一个参数是正则表达式,并且包含分组,那么在replace()的第二个参数中,可以通过$1$2这种形式引用分组匹配结果。
1
2
3
4
    var num = '123456789'
    var reg = /(\d)(?=(?:\d{3})+$)/g
    num.match(reg) // ["3", "6"]
    console.log(num.replace(reg,'$1,')) // '123,456,789'

## 判断字符串是否包含数字

### .

  • 匹配除换行符\n外的任意字符,如果要匹配任意字符,应该用/[.\n]*/
1
2
3
4
5
    var reg = /.*\d+.*/
    var str1 = 'abc'
    var str2 = 'ab123c'
    reg.test(str1) // false
    reg.test(str2) // true

## 判断是否符合USD格式

### USD

  • USD是美元数额的一种表示格式,该格式要求字符串符合以下特征:1. 以 $ 开始 2. 千分位分隔符 3. 如果为小数,则小数部分长度为 2

根据规则 /^\$/ $开头,中间部分如果不为0,那么不会以0开头/[1-9]\d*|0/,考虑千分位分隔符,每3位前面有个,,并且3位前有数字/[1-9](,\d{3})*,从右往左最后一个,前肯定有1-3位数字/[1-9]\d{0,2}/,然后将所有的组合起来/^\$([1-9]\d{0,2}(,\d{3})*|0)/,接下来考虑小数,小数是.开头,后面加2位数字,并且可能存在0个或1个,/\.\d{2}?/,最后再组合,/^\$([1-9]\d{0,2}(,\d{3})*|0)(\.\d{2})?$/

1
2
3
4
5
6
7
8
9
10
11
  var reg = /^\$([1-9]\d{0,2}(,\d{3})*|0)(\.\d{2})?$/
  var USDList = [
    '$1.23',
    '0',
    '$23',
    '$0',
    '$0.34'
  ]
  USDList.forEach(USD => {
    console.log(reg.test(USD))
  }) // true  false true true true

## 获取url参数

### \w

  • \w用于匹配单词字符,包含0-9a-zA-z以及下划线_,等价于[A-Za-z0-9_]

来看一个url链接,http://xxx.com?name=zhangsan&age=3,参数以=分割前后是单词字符。

1
2
3
4
5
6
7
8
9
10
    // 获取全部url参数
    var reg = /(\w+)=(\w+)/g
    var url = 'http://xxx.com?nameA=zhangsan&age=3'
    // a为匹配到的字符串
    // b、c是a后面是按照分组从左往右顺序的参数
    var query = {}
    url.replace(reg, (a, b, c) => {
      query[b] = c
    })
    console.log(query) // {name: "zhangsan", age: "3"}
1
2
3
4
5
6
7
8
    // 获取指定url参数
    function getQueryByKey(key) {
      // 指定参数左侧为?或者是&,指定参数右侧是’=‘ + 不定字符 以&结尾或者空结尾
      var url = 'http://xxx.com?nameA=zhangsan&age=3'
      var reg = new RegExp(`(\?|&)${key}=(\w+|)`)
      var param = url.match(reg)
      return param[2]
    }

## 验证邮箱 邮箱格式: 1. 邮件名称:只允许英文字母、数字、下划线、以及中划线组成。/[\w-]/ 2. 域名:N级域名.二级域名.顶级域名/[\w-]+(\.[\w-]+)+/ 3. 最终表达式:名称@域名/^[\w-]+@[\w-]+(\.[\w-]+)+$/

## 验证身份证号码 身份证号码格式: 1. 第二代身份证,18位 XXXXXX yyyy MM dd xxx x 2. 第一代身份证,15位 XXXXXX yy MM dd xxx

  • 1-6位是地区编码,7-14位是出生年月日,一代身份证年份为2位,15-18位是顺序码+校验码,一代身份证没有校验码。
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
  // 18位身份证
  // 前6位地区编码,非0开头
  /[1-9]\d{5}/
  // 年份1800-2999
  /(18|19|(2\d))\d{2}/
  // 月份
  /(0[1-9])|(1[012])/
  // 日期
  /([0-2][1-9])|10|20|30|31/
  // 顺序码+校验码
  /\d{3}[\dXx]/

  // 15位身份证
  // 前6位地区编码,非0开头
  /[1-9]\d{5}/
  // 年份00-99
  /\d{2}/
  // 月份
  /(0[1-9])|(1[012])/
  // 日期
  /([0-2][1-9])|10|20|30|31/
  // 顺序码+校验码
  /\d{3}/

  // 结合起来
  /(^[1-9]\d{5}(18|19|(2\d))\d{2}((0[1-9])|(1[012]))(([0-2][1-9])|10|20|30|31)\d{3}[\dXx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(1[012]))(([0-2][1-9])|10|20|30|31)\d{3}$)/

匹配汉字

/[\u4e00-\u9fa5]/或者/[^\x00-\xff]/