正则

 

创建形式

  • 正则表达式有两种定义方式,一种是通过以/开头和/结束的字符串字面量,另一种是通过new和RegExp关键字来生成

    // 构造函数创建
    const regexp = new RegExp("内容", "修饰符")
    // 直接创建 - 字面量模式
    const regexp = /.../
    

元字符

  • \d:一位数字
  • \D:除数字外的任意字符
  • \w:数字、字母和下划线
  • \W:除数字、字母和下划线以外的字符
  • \s:表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符
  • \S:非空白字符
  • .:通配符,除换行外,可表示任意字符
  • \r:回车符
  • \n:换行符
  • \t:制表符
  • \f:换页符
  • \v:垂直制表符
  • \p:检测字符属性
  • []:原子表,其中. + ()不被转义,不用反斜杠
  • ():原子组
使用时要被转义的元字符:([{\^$、** ?*+.)]}**

字符属性(统一大写,写于\p后边)

  • {P}:标点字符
  • {L}:字母
  • {M}:标记符号(一般不会单独出现)
  • {Z}:分隔符(比如空格、换行等)
  • {S}:符号(比如数学符号、货币符号等)
  • {N}:数字(比如阿拉伯数字、罗马数字等)
  • {C}:其他字符
  • {sc=xxx}:指定语言系统

量词

  • {m,}:至少出现m次
  • {m}:出现m次,等价于{m,m}
  • {m,n}:至少出现m次,最多出现n次
  • ?:对问号前一个字母或元素进行处理 - 出现0次或一次,等价于{0,1}
  • +:至少出现一次,等价于{1,}
  • *:出现任意次,等价于{0,}
  • ?的妙用(禁止贪婪)/\d{3,6}/g会匹配尽可能多满足要求的字符,/\d{3,6}?/g会匹配最少的满足要求的字符,就是说3-6个范围内的数字都会被匹配,但是如果先匹配了3个就不会继续往下匹配了,可以加** + {} ?后边,取区间最小值

位置

  • ^:匹配开头,若放在原子表里,表示取反
  • $:匹配结尾,多行匹配中匹配行末尾
  • \b:匹配单词边界,匹配\w和\W之间的位置,比如’123w_1 wei.123’这个字符串’123w_1’,’wei’,’123’属于3个单词,这3个单词的开头和结尾的位置就属于单词边界
  • \B:非单词边界,除了上面的那些位置都是非单词边界

断言

  • (?=内容):匹配内容后边是内容的对应内容值,不是组
  • (?<=内容):匹配内容前边是内容的对应内容值,不是组
  • (?!内容):匹配内容后边不是内容的对应内容值,不是组
  • (?<!内容):匹配内容前边不是内容的对应内容值,不是组

修饰符

  • g:全局查找
  • s:忽略换行符
  • i:不区分大小写
  • m:多行查找
  • u:Unicode模式,正确处理四个字节(宽字节)的UTF-16编码
  • y:粘附模式,从零开始(通过设置lastIndex来指定开始位置),若匹配到了就继续匹配,直到下一个匹配值不是时,停止匹配,在一定程度上节省性能

原子组

  • ()框起来的内容代表分组,例如需匹配连续出现的abc,就需要使用/(abc)+/
  • 原子组中的|代表或者关系,例如(p1|p2)可代表匹配模式p1或者模式p2
  • 引用分组(捕获组):
    • 添加括号的分组可以被引用
    • 在正则表达式中还可以使用\1,\2,\3等来引用前面的分组
    • 正则表达式/\d{4}(-|/|.)\d{2}\1\d{2}/中的\1代表(-|/|.)这个分组的匹配结果,即前面是-后面也是-,前面是/后面也是/,前面是.后面也是.

      /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/
      //匹配2021/01.31 2021/01/31 2021-01-31 2021.01.31等-/.的随意组合
      /\d{4}(-|\/|\.)\d{2}\1\d{2}/
      // 只匹配2021/01/31 2021-01-31 2021.01.31这三种
      
  • 非捕获分组:
    • 引用分组可以通过$1/1取到为捕获型分组,非捕获型分组只用来分组但不可取,非捕获分组使用(?:)
    • ?:写在组的最前方,表示对该组不进行记录,故没有该组的值
    • 注:使用.match()来匹配时,不加全局搜索
    • 使用exec()匹配时,可以用全局
const string = "ababa abbb ababab"
string.match(/(?:ab)+/g) // ['abab', 'ab', 'ababab']
RegExp.$1 // ''
string.match(/(ab)+/g) // ['abab', 'ab', 'ababab']
RegExp.$1 // 'ab'
  • ?<组别名>
    • 写在组的开始,给组起别名使用时,直接写对应的$<别名>就可以获取

转义:有特殊意义的符号需要进行转义,如 . / 等,加 \ 进行转义

特殊符号

  • $`
    • 正则
      • 构造函数属性
      • .leftContext的简写
      • 第一次匹配内容前面的内容
    • 字符串(.replace()仅用于字符型替换)
      • 匹配内容前面的值,用于替换当前匹配到的值
  • $'
    • 正则
      • 构造函数属性
      • .rightContext的简写
      • 获取匹配到的内容后边的内容
    • 字符串(.replace()仅用于字符型替换)
      • 匹配内容后边的值,用于替换当前匹配到的值
  • $&
    • 正则
      • 构造函数属性
      • .lastMatch简写
      • 最后匹配的内容
    • 字符串(.replace()仅用于字符型替换)
      • 匹配到的内容
  • $_:正则属性
    • 构造函数属性
    • .input的简写
    • 最后搜索的字符串
  • $+:正则属性
    • 构造函数属性
    • .lastParen的简写
    • 最后匹配到的捕获组值,若无原子组,则返回空
    • 可以通过$1 $2 $3 $4 …等来获取指定位置的组
  • $$:字符串(.replace()仅用于字符型替换)
    • $
  • $n:字符串(.replace()仅用于字符型替换)
    • 匹配第n个捕获组字符串,n取值为1~9
    • 若无组,则直接输出$n
  • $nn:字符串(.replace()仅用于字符型替换)
    • 匹配第nn个捕获组字符串,nn取值为01~99
const patten = /(a)t/igs
const src = 'bat, aat, cat, vsat'
// 正则
if (patten.test(src)) {
  console.log(RegExp.$_)
  console.log(RegExp.input) // bat, aat, cat, vsat
  console.log(RegExp["$`"])
  console.log(RegExp.leftContext) // b
  console.log(RegExp["$'"])
  console.log(RegExp.rightContext) // , aat, cat, vsat
  console.log(RegExp["$&"])
  console.log(RegExp.lastMatch) // at
  console.log(RegExp["$+"]) // a
  console.log(RegExp.$1) // a
}
// 字符串
console.log(src.replace(patten, "$1")) // ba,aa, ca, vsa
console.log(src.replace(patten, "$01")) // ba,aa, ca, vsa
console.log(src.replace(patten, "$$")) // b$,a$, c$, vs$
console.log(src.replace(patten, "$`")) // bb,abat,a, cbat,aat, c, vsbat,aat, cat, vs
console.log(src.replace(patten, "$1'")) // b,aat, cat, vsat,a, cat, vsat, c, vsat, vs
console.log(src.replace(patten, "$&")) // bat,aat, cat, vsat
src.replace(patten, (a,b,c,d,e)=> {
  // 基础三个参数,后续每个组别为一个中间参数
    // 第一个参数是匹配到的值
    // 倒数第二个参数是匹配到的值的位置(从零开始计算)
    // 最后一个参数是全字符串
    // 中间的都是组别匹配到的值
  console.log(a) // at ...
  console.log(b) // a ...
  console.log(c) // 1 ...
  console.log(d) // bat,aat, cat, vsat, aaa ...
  console.log(e) // undefined ...
})

正则属性及方法

属性

  • lastIndex:整数,源字符串中,下一次搜索的开始位置,默认始终为0
    • 当使用全局匹配时,该属性的值为匹配到的
    • 必须使用正则的方法才有用,再一个数组中.match()中是无效的
    • 若没有使用全局的匹配,返回值一直是第一个匹配到的位置
    • 使用全局匹配时,每次返回匹配到的下一个的位置
    • 要先调用对应的正则匹配方法,再调这个属性,否则只会返回零
    • 若没有匹配的的正则值,则也返回零
      const str = 'asdfavghanh'
      const regular = /a/g
      regular.exec(str) // 返回第一个匹配到的值
      regular.lastIndex // 返回第一个匹配到的值的位置
      regular.exec(str) // 返回第二个匹配到的值
      regular.lastIndex // 返回第二个匹配到的值的位置
      regular.exec(str) // 返回第累计的下一个匹配到的值
      regular.lastIndex // 返回匹配到的值对应的位置
    
  • global:布尔值,是否设置g标记
  • ignoreCase:布尔值,是否设置i标记
  • unicode:布尔值,是否设置u标记
  • sticky:布尔值,是否设置y标记
  • multiline:布尔值,是否设置m标记
  • dotAll:布尔值,是否设置s标记
  • source:正则表达式中的字面量字符串,没用开始和结束的斜杠
  • flags:正则表达式的标记字符串,没有斜杠
const patten = /at/igs
console.log(patten.global) // true
console.log(patten.ignoreCase) // true
console.log(patten.unicode) // false
console.log(patten.sticky) // false
console.log(patten.multiline) // false
console.log(patten.dotAll) // true
console.log(patten.source) // at
console.log(patten.flags) // igs

方法

  • .test()
    • 语法:正则.test(字符串)
    • 在字符串中搜索符合正则的内容,搜索到返回true
    • 搜索失败就返回false
      regular.test(str)
    
  • .exec()
    • 语法:正则.exec(字符串)
    • 只接收一个参数
    • 找到匹配项,返回包含第一个的详细信息数组,不管是不是全局匹配,都只会得到一个详细数组值
      • 返回数组的第一个值为匹配项,其余为原子组的捕获值
      • 数组具有额外属性index input
        • index:匹配到的值的起始位置
        • input:查找的整体字符串
    • 不加全局,永远匹配第一个,加全局,重复调用,每次匹配下一个
    • 找不到,则返回null
      regular.exec(str)
        
      const str = '2021-01-31'
      const reg1 = /\d{4}-\d{2}-\d{2}/
      const reg2 = /(\d{4})-(\d{2})-(\d{2})/
      str.match(reg1) // ['2021-01-31', index: 0, input: '2021-01-31', groups: undefined]
      str.match(reg2) // ['2021-01-31', '2021', '01', '31', index: 0, input: '2021-01-31', groups: undefined]
      console.log(RegExp.$1)
      // '2021'
    

字符串的方法(正则部分)

  • .search()
    • 语法:字符串.search(正则)
    • 在字符串中搜索符合规则的内容,搜索成功就返回第一个值的位置
    • 匹配失败时返回-1
      str.search(regular)
    
  • .match()
    • 语法:字符串.match(正则)
    • 查找符合正则的字符串
    • 一般加全局搜索
    • 不加全局收索时返回值和.exec()返回值一样,匹配的第一个匹配值及捕获组的值
      • 第一个元素是整体匹配结果
      • 第二个及之后的是各个分组匹配的内容
      • 后边有俩额外参数
    • 加全局搜索时,返回匹配到的所有值(仅匹配到的值)
    • 返回数据类型为数组
      str.match(regular)
    
  • .replace()
    • 语法:字符串.replace(正则,新的字符串/回调函数)
    • .match()方法一样,搜索符合规则的内容,替换成对应的字符串。
    • 返回替换后的内容。
    • 第二个参数可以是回调函数(基础三个参数,后续每个组别为一个中间参数)
      1. 第一个参数是匹配到的值
      2. 倒数第二个参数是匹配到的值的位置(从零开始计算)
      3. 最后一个参数是全字符串
      4. 中间的都是组别匹配到的值
      // 字符串型替换
      str.replace(regular, '')
      // 函数型替换
      str.replace(regular, (v,r,s) => {})
    

使用示例及常用正则

  • 常用正则

      // 提取数字 - 获得数组
      let key = str.match(/\d/g)
      // 提取汉字 - 获得数组
      let text = str.match(/[^ -~]/g)
      // 提取字母 - 获取数组
      let value = str.match(/[a-z]/ig); 
      // 获取指定区域中的内容
      let str = /<style>[\s\S]*<\/style>/.exec('指定字符串')
      // 匹配标点符号,修饰符u必须带
      let str = str.match(/\p{P}/gu)
      // 匹配字母,修饰符u必须带
      let str = str.match(/\p{L}/gu)
      // 匹配汉字,修饰符u必须带
      let str = str.match(/\p{sc=Han}/gu)
    

常用正则


// 非负整数:
^\d+$
 
// 正整数:
^[0-9]*[1-9][0-9]*$
 
// 非正整数:
^((-\d+)|(0+))$
 
// 负整数:
^-[0-9]*[1-9][0-9]*$
 
// 整数:
^-?\d+$
 
// 非负浮点数:
^\d+(\.\d+)?$
 
// 正浮点数 : 
^((0-9)+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)$
 
// 非正浮点数:
^((-\d+\.\d+)?)|(0+(\.0+)?))$
 
// 负浮点数:
^(-((正浮点数正则式)))$
 
// 英文字符串:
^[A-Za-z]+$
 
// 英文大写串:
^[A-Z]+$
 
// 英文小写串:
^[a-z]+$
 
// 英文字符数字串:
^[A-Za-z0-9]+$
 
// 英数字加下划线串:
^\w+$
 
// E-mail地址:
^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$
 
// URL:
^[a-zA-Z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\s*)?$ 
// OR
// ^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$

// 邮政编码:
^[1-9]\d{5}$
 
// 中文:
^[\u0391-\uFFE5]+$
 
// 电话号码:
^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$
 
// 手机号码:
^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$
 
// 双字节字符(包括汉字在内):
^\x00-\xff
 
// 匹配首尾空格:
(^\s*)|(\s*$)像vbscript那样的trim函数
 
// 匹配HTML标记:
<(.*)>.*<\/\1>|<(.*) \/>
 
// 匹配空行:
\n[\s| ]*\r
 
// 提取信息中的网络链接:
(h|H)(r|R)(e|E)(f|F)  *=  *('|")?(\w|\\|\/|\.)+('|"|  *|>)?
 
// 提取信息中的邮件地址:
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
 
// 提取信息中的图片链接:
(s|S)(r|R)(c|C)  *=  *('|")?(\w|\\|\/|\.)+('|"|  *|>)?
 
// 提取信息中的IP地址:
(\d+)\.(\d+)\.(\d+)\.(\d+)
 
// 提取信息中的中国手机号码:
(86)*0*13\d{9}
 
// 提取信息中的中国固定电话号码:
(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}
 
// 提取信息中的中国电话号码(包括移动和固定电话):
(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}
 
// 提取信息中的中国邮政编码:
[1-9]{1}(\d+){5}
 
// 提取信息中的浮点数(即小数):
(-?\d*)\.?\d+
 
// 提取信息中的任何数字 :
(-?\d*)(\.\d+)? 
 
// IP:
(\d+)\.(\d+)\.(\d+)\.(\d+)
 
// 电话区号:
/^0\d{2,3}$/
 
// 腾讯QQ号:
^[1-9]*[1-9][0-9]*$
 
// 帐号(字母开头,允许5-16字节,允许字母数字下划线):
^[a-zA-Z][a-zA-Z0-9_]{4,15}$
 
// 中文、英文、数字及下划线:
^[\u4e00-\u9fa5_a-zA-Z0-9]+$
 
// 匹配中文字符的正则表达式: 
[\u4e00-\u9fa5]
 
// 匹配双字节字符(包括汉字在内):
[^\x00-\xff]
 
// 匹配空行的正则表达式:
\n[\s| ]*\r
 
// 匹配HTML标记的正则表达式:
/<(.*)>.*<\/\1>|<(.*) \/>/
 
// sql语句:
^(select|drop|delete|create|update|insert).*$
 
// 匹配首尾空格的正则表达式:
(^\s*)|(\s*$)
 
// 匹配Email地址的正则表达式:
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*