js正则表达式简单操作

javascript正则表达式

大部分内容我是从b站上学习的
这是视频连接

js创建正则对象两种方式

1.字面量的方式

let reg =/d+/

2.以对象的方式创建(这里需要转译)

    let reg=new RegExp("\\d+")

js创建两种对象的区别

//1.两个斜杠中间包起来的都是元字符(如果正则中要包含某个变量的值,则不能使用字面量的方式创建)
    let type = 'hello'
    let reg = /^@"+type+"@$/;
    reg.test('@hello@')//false
    let reg2 = new RegExp("^@" + type + "@$");
    reg2.test('@hello@')//true

正则表达式由两部分组成

1.元字符

  • 量词元字符:设置出现的次数
    * 零到多次
    + 一到多次
    ? 零到一次
    {n} 出现n次
    {n,} 出现n到多次
    {n,m} 出现n到m次
  • 特殊元字符:单个或者组合在一起代表特殊的含义
    \ 转义字符(普通->特殊->普通)
    . 除\n(换行符)以外的任何字符
    ^ 以哪一个元字符作为开始
    $ 以哪一个元字符作为结束
    \n 换行符
    \d 0-9 之间的一个数字
    \D 非0-9之间的一个数字(大写和小写的意思是相反的)
    \w 数字,字母,下划线中的任意一个字符等价于[A-Za-z0-9_]
    \W 匹配任何来自非单词字符。等价于[^A-Za-z0-9_]
    \s 匹配任何空白字符,包括空格,制表符,换页符等等。等价于[\f\n\r\t\v]。
    \S 匹配热河非空白字符。等价于[^\f\n\r\t\v]
    \b匹配一个单词的边界
    \t 一个制表符(一个TAB键:四个空格)
    x|y x或者y中的一个字符
    [xyz] x或者y或者z中的一个字符
    [^xy] 非xy以外的任意一个字符
    [a-z] 指定a-z这个范围中的任意字符
    [^a-z] 非a-z这个范围中的任意字符
  • ()正则中的分组符号
    (?:)只匹配不捕获
    (?=)正向预查
    (?!)反向预查
  • 普通元字符:代表本身含义的
    /zhangsan/ 此处匹配的就是本身

2.修饰符

  • i&m&g
    i=>ignoreCase 忽略单词大小写匹配
    m=>multiline 可以进行多行匹配
    g=>global 全局匹配
    y=>

代码示例

^/$
1.两者都加,表示字符串只能匹配和规则一致的内容
 let reg = /^\d+$/
 let result = reg.test('1141')
 //=>result=true
2.单独使用其中一者
 let reg = /\w+\d+$/
 let result = reg.test('qe12')
 //=>result=true
 let reg = /^\d+/
 let result = reg.test('1141q1')
 //=>result=true
 let reg = /\d+$/
 let result = reg.test('qwe111')
 //=>result=true
|
let reg=/^18|19/
reg.test('18')
reg.test('29')
reg.test('129')
reg.test('189')
reg.test('1829')
reg.test('829')
reg.test('182')
//=>结果全为true
因为x|y会存在优先级问题,所以一般写得时候需要伴随者小括号进行分组,因为小括号会改变处理的优先级
 let reg = /^(18|29)$/
 result = reg.test('18')//=>result=true
 result = reg.test('29')//=>result=true  
 result = reg.test('129')//=>result=false
 result = reg.test('189')//=>result=false
 result = reg.test('1829')//=>result=false
 result = reg.test('829')//=>result=false
 result = reg.test('182')//=>result=false
[ ]
1.[ ]里的内容只有A-Za-z0-9代表范围,其余都带表为可能出现的内容
let reg=/^[@+]+$/
reg.test('@@') //true
reg.test('@+') //true
let reg=/^[@+]$/
reg.test('@') //true
reg.test('@+')//true
reg.test('@@')//false
reg.test('@+')//false
let reg=/^[\d]+$/
reg.test('d') //false
reg.test('\\') //false
reg.test('9') //true
let reg=/^[\\d]+$/ //这里\将\进行了转义,所有[]内容为\d
reg.test('d') //true
reg.test('\\') //true
reg.test('9') //false
2.[ ]中不能存在多位数
let reg=/^[0-9]+$/
reg.test('0')//true
reg.test('1')//true
reg.test('3')//true
reg.test('8')//true
reg.test('-')//false
let reg=/^[10-29]+$/ //并不能表示10-29的范围,只能表示1,0,2,9,这几个数字和下划线
reg.test('10')//true
reg.test('20')//true
reg.test('13')//false
reg.test('18')//false
reg.test('-')//false
reg.test('1-')//false
reg.test('-2')//false
3. ?在正则中的五大作用
  • 问号左边是非量词元字符:本身代表量词元字符,出现零到一次

  • 问号左边是量词元字符:取消捕获时候的贪婪性

  • (?:)z只匹配不捕获 (?:x)称为非捕获组(Non-capturing group),表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。非捕获组的作用请考虑这样一个场景,假定需要匹配foo或者foofoo,正则表达式就应该写成/(foo){1, 2}/,但是这样会占用一个组匹配。这时,就可以使用非捕获组,将正则表达式改为/(?:foo){1, 2}/,它的作用与前一个正则是一样的,但是不会单独输出括号内部的内容。

    var m = 'abc'.match(/(?:.)b(.)/);
    m // ["abc", "c"]
    

    上面代码中的模式,一共使用了两个括号。其中第一个括号是非捕获组,所以最后返回的结果中没有第一个括号,只有第二个括号匹配的内容。下面是用来分解网址的正则表达式。

    // 正常匹配
    var url = /(http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/;
    url.exec('http://google.com/');
    // ["http://google.com/", "http", "google.com", "/"]
    // 非捕获组匹配
    var url = /(?:http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/;
    url.exec('http://google.com/');
    // ["http://google.com/", "google.com", "/"]
    
  • (?=)正向预查 x(?=y)称为先行断言(Positive look-ahead),x只有在y前面才匹配,y不会被计入返回结果。比如,要匹配后面跟着百分号的数字,可以写成/\d+(?=%)/ “先行断言”中,括号里的部分是不会返回的。

    var m = 'abc'.match(/b(?=c)/)
    m // ["b"]
    
  • (?!)负向预查 x(?!y)称为先行否定断言(Negative look-ahead),x只有不在y前面才匹配,y不会被计入返回结果。比如,要匹配后面跟的不是百分号的数字,就要写成/\d+(?!%)/。

    /\d+(?!\.)/.exec('3.14') // ["14"]
    

    上面代码中,正则表达式指定,只有不在小数点前面的数字才会被匹配,因此返回的结果就是14。“先行否定断言”中,括号里的部分是不会返回的

    var m = 'abd'.match(/b(?!c)/)
    m // ['b']
    

常用的正则表达式

1.验证是否为有效数字

规则分析
1. 可能出现+,-号,也有可能不出现
2. 如果只有一位0-9范围内的数字都可以,多位则首位不能为0
3. 小数部分可能有可能没有,如果有则必须为小数点+数字

let reg=/^[+-]?(\d|([1-9]\d+)(\.\d+)?$/
2.验证密码

规则分析
1. 数字,字母,下划线
2. 6-16位

function CheckPassword(value) { //以前的方法
      if (value.length < 6 || val.length > 16) {
        alert('长度必须介于6-16位之间');
        return
      }
      let area = ['@','*','-','a', 'b', 'c', ...rest]
      for (let i = 0; i < value.length; i++) {
        //判断是否存在传入的value和area字符是否有不一样
      }
    }

//验证简单密码
let reg = /^\w{6,16}$/
3.验证是否是真实姓名
  let reg = /^[\u4e00-\u9FA5]{2,10}(.[\u4e00-\u9FA5]+)?$/
4.验证是否为邮箱

规则分析
1.开头是数字字母下划线(1到多位)
2.还可以是 -、数字、字母、下划线、.数字字母下划线,整体零到多次
3.邮箱的名字由"数字、字母、下划线、-、.几部分组成,但是-/,不能连续多次出现"

let reg=/^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
5.身份证号码

规则分析
1.前6位为地区编号
2.7到10位为出生年份
3.11到12位为出生月份
4.13到14位为出生日期
5.倒数第二位判断男女
6.最后一位为\d|x

let reg=/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(?:\d|x)$/
6.把时间字符串进行处理
let time='2019-09-03'
let reg=/^(\d{4})-(\d{1,2})-(\d{1,2})$/
time=time.replace(reg,"$1年$2月$3日")//=>2019年9月3日
/*
还可以这样处理[str].replace([reg],[function])
1.首先拿REG和TIME进行匹配捕获,能匹配到几次就会把传递的函数执行几次(而且是匹配一次执行一次)
2.不仅把方法执行,而且REPLACE还给方法传递了实参信息(和exec捕获的内容一致的信息:大正则匹配的内容,小分组匹配的信息...)
3.在函数中我们返回的是啥,就把当前大正则匹配的内容替换
*/
time = time.replace(reg, (...arg) => {
      let [, $1, $2, $3] = arg
      $2.length < 2 ? $2 = "0" + $2 : null
      $3.length < 2 ? $3 = "0" + $3 : null
      return $1 + "年" + $2 + "月" + $3 + "日"
})
7.单词首字母大写
let str="good good study. day day up!"
let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g
//=>函数被执行了六次,每一次都把正则匹配信息传递给函数
//=>每一次ARG:["good","g"]["good","g"]["study","s"]...
str = str.replace(reg, (...arg) => {
    let [content, $1] = arg
    $1 = $1.toUpperCase()
    content = content.substring(1)
    return $1 + content
  })
8.验证一个字符串中那个字母出现的次数最多,多少次
let str='helloWorldHello'
/*
简单思维
*/
let obj=[]
[].forEach.call(str,char=>{
  if(typeof obj[char]!=="undefined"){
    obj[char]++
    return;
  }
  obj[char]=1
})
//使用正则
let str="efaadfaeeadq"
str=str.split('').sort((a,b)=>a.localeCompare(b)).join(''));
let reg=/([a-zA-Z])\1+/g
let ary=str.match(reg)
ary.sort((a,b)=>{
  return b.length-a.length
})

let max=ary[0].length,
res=[ary[0].substring(0,1)]
for (let i = 1; i < ary2.length; i++) {
      let item = ary2[i]
      if (item.length < max) {
        break
      }
      res2.push(item.substring(0, 1))
    }
  console.log(`出现次数最多的字符:${res}出现了${max}次`)
//使用正则2
let str = "eeefadsfadfdfddfd",
      max = 0,
      res = [],
      flag = false
    str = str.split('').sort((a, b) => a.localeCompare(b)).join('')
    console.log(str)
    for (let i = str.length; i > 0; i--) {
      let reg = new RegExp(`([a-zA-Z])\\1{${(i-1)}}`, 'g')
      str.replace(reg, (content, $1) => {
        res.push($1)
        max = i;
        flag = true
      })
      if (flag) break
    }
console.log(`出现次数最多的字符:${res}出现了${max}次`)
9.使用正则格式化日期和URL
~ function () {
      function formatTime(template = "{0}年{1}月{2}日 {3}时{4}分{5}秒") {
        let timeAry = this.match(/\d+/g)
        console.log(timeAry)
        return template.replace(/\{(\d+)\}/g, (...[, $1]) => {
          let time = timeAry[$1] || "00"
          return time.length < 2 ? "0" + time : time
        })
      }

      function queryURLParams() {
        let obj = {}
        this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, $1, $2]) => {
          obj[$1] = $2
        })
        this.replace(/#([^?=&#]+)/g, (...[, $1]) => {
          obj['HASH'] = $1
        })
        return obj
      }

      ['formatTime', 'queryURLParams'].forEach(item => {
        String.prototype[item] = eval(item)
      })
    }()
    let time = "2019-9-4 16:51:3"
    console.log(time.formatTime())
    console.log(time.formatTime("{0}年{1}月{2}日"))
    console.log(time.formatTime("{1}-{2} {3}-{4}"))

    //queryURLParams:获取URL地址问号和面的参数信息(可能也包含hash值)
    let url = "http://www.baidu.com?x=12jkadfl&form=asldfk#video"
    console.log(url.queryURLParams())
10.千分符
//普通方式来做
let num="112345678256874"
num=num.split('').reverser().join('')
for(let i=2;i<num.length-1;i+=4){
  let prev=num.substring(0,i+1),
      next=num.substring(i+1)
    num=prev+","+next
}
num=num.split('').reverse().join('');
console.log(num)
//正则方式

String.prototype.millimeter = millimeter
let num2 = "112345678256874"
function millimeter() {
  return this.replace(/\d{1,3}(?=(\d{3})+$)/g, content => {
        return content + ','
   })
}
console.log(num2.millimeter())
11.正则匹配文件名
/.+\\(.+)$/

正则捕获的懒惰和贪婪性

正则的捕获
1.正则Rep.prototype上的方法
exec
test
2.字符串String.prototype上支持正则表达式处理的方法
replace
match
spite

贪婪性
let str="helloWorld1998@0522@link"
//=>正则捕获的贪婪性:默认情况下,正则捕获的时候是按当前所匹配的最长结果来获取的
let reg=/\d+?/g //=>(9) ["2", "0", "1", "9", "1", "9", "2", "1", "1"]
//这里在量词后面设置?表示捕获的时候取消贪婪性(按照正则匹配的最短结果来获取)
str.match(reg)
懒惰性
let str="hello19129world2910"
let reg=/\d+/
let reg2=/\d+/g
reg.exec(str)
/*
Array(1)
0: "19129"
groups: undefined
index: 8        这里是数字开始的索引
input: "hello19129world2910"
length: 1
__proto__: Array(0)
*/
reg.lastIndex //0
//=>这里因为没有加g修饰符,所以每执行一次exec只能捕获到一个符合规则,默认情况下lastIndex最后为0,这就是正则捕获的懒惰性
reg2.exec(str)
/*
0: "19129"      第一个匹配到的索引字符串的开始位置
groups: undefined
index: 8       这里是索引字符串开始的索引
input: "hello19129world2910"
length: 1
__proto__: Array(0)
*/
reg2.lastIndex //13 这是索引字符串的最后一个字符索引
reg2.exec(str)
/*
0: "2910"
groups: undefined
index: 19
input: "hello19129world2910"
length: 1
__proto__: Array(0)
*/
reg2.lastIndex //23
String.prototype.match()的实现
let reg = /\d+/g;
    ~ function () {   //匿名函数的直接调用
      function execAll(str = "") {
        if (!this.global) return this.exec(str) //判断是否存在全局g修饰符
        let ary = []
        res = this.exec(str);
        while (res) {
          ary.push(res[0]);
          res = this.exec(str)
        }
        return ary
      }
      RegExp.prototype.execAll = execAll
    }()
    reg.execAll("hello19129world2910")
    /*
    0: "19129"
    1: "2910"
    length: 2
    __proto__: Array(0)
    */
    "hello19129world2910".match(reg)
     /*
    0: "19129"
    1: "2910"
    length: 2
    __proto__: Array(0)
    */

分组捕获和分组引用

分组捕获
let str = '50022720001121000X'
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(?:\d|X)$/  //这里(?:)取消了捕获
reg.exec(str)
str.match(reg)
/*
0: "50022720001121000X"
1: "500227"
2: "2000"
3: "11"
4: "21"
5: "00"
6: "0"
groups: undefined
index: 0
input: "50022720001121000X"
length: 7
__proto__: Array(0)
*/
replace字符串中实现替换的方法(一般都是伴随正则一起使用的)
let str='helloWorld@78128@helloWorld'
str.replace(/helloWorld/g,'hahaha') //=>hahaha@78128@hahaha
分组引用
let str="book"
let reg=/^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/
//=>分组引用就是通过"\数字"让其代表和对应分组出现一模一样的内容
reg.test('book')//true
reg.test('deep')//true
reg.test('depp')//false
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值