JS正则表达式详解

前言

在H5开发中,正则表达式有很多地方都用得到,固整理了正则表达式的基本规则,和在JS中如何使用正则表达式,做了简单的介绍。

1、正则常用字符
  • ^:匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 'n' 或 'r' 之后的位置。
  • $:匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 'n' 或 'r' 之前的位置。
  • (?=x): 表示位于字符前是否是x。例如,'hello'.replace(/(?=l)/,'#') 得到 'he#l#lo'
  • (?!=x): 表示位于字符前为非x。 例如,'hello'.replace(/(?=l)/,'#') 得到 '#h#ell#o'。
  • {n}:n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
  • {n,}:n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
  • {n,m}:m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
  • *:匹配前面的子表达式零次或多次。例如,zo 能匹配 "z" 以及 "zoo"。 等价于{0,}。
  • +:匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
  • ?:匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是惰性匹配。惰性匹配尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
  • .:就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号...中的每个点,都可以理解成占位符,表示任何类似的东西。
  • x|y:匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
  • [xyz]:字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
  • [^xyz]:负值字符集合。匹配未包含的任意字符。例如, /[^abc]/ 可以匹配 'd' 不能匹配 'a'。
  • [a-z]:字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
下列特殊字符大小写为取反来理解
  • \b:匹配一个单词边界,也就是指单词和空格间的位置。例如, 'erb' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
  • \B:匹配非单词边界。'erB' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
  • \d: 匹配一个数字字符。等价于 [0-9]。
  • \D: 匹配一个非数字字符,等价于 [^0-9]
  • \w: 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'
  • \W: 匹配除了\w所包含的字符
  • \s: 匹配任何空白字符,包括空格、制表符、换页符等等
  • \S: 匹配除了\s所匹配的字符
特殊字符
  • \f: 匹配一个换页符。等价于 x0c 和 cL。
  • \n: 匹配一个换行符。等价于 x0a 和 cJ。
  • \r: 匹配一个回车符。等价于 x0d 和 cM。
  • \t: 匹配一个制表符。等价于 x09 和 cI。
  • \v: 匹配一个垂直制表符。等价于 x0b 和 cK。
  • \cx:匹配由 x 指明的控制字符。例如, cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
2、js正则表达式运用
1.修饰符
  • /g: 全局匹配,不会匹配一个后就停止
  • /i: 忽略大小写匹配
  • /m: 支持多行匹配
  • /u: Unicode模式(ES6),也可以这样使用/\u{65}/标明大括号里面是unicode
2.常用api
  • js用RegExp表示正则表达式,创建RegExp如下
//直接创建对象,/^h/里面为正则式 g为修饰符
let reg = /^h/g
//使用构造函数创建, 第一个参为为正则式,第二个参数为修饰符
let reg = new RegExp('xyz', 'i')
//或者,等同上
let reg = new RegExp(/xyz/i)
  • RegExp 方法
  1. test()用于检测一个字符串是否匹配某个模式.如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false
let reg = /\d/g
reg.test('11234') //true
reg.test('adfd') //false
  1. exec() 如果exec()找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string.
    eg:非全局正则表达式
let reg = /En(glish)/
let ret = reg.exec('Speak English')
//ret[0] -> English
//ret[1] -> En
//ret.index -> 6
//input: "speak English"
console.log(ret) 

当 RegExpObject 是一个全局正则表达式时,exec() 的行为就稍微复杂一些。它会在RegExpObject的 lastIndex属性指定的字符处开始检索字符串 string。当 exec()找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当exec() 再也找不到匹配的文本时,它将返回null,并把lastIndex 属性重置为 0。
eg:全局正则表达式

let reg = /e/gi
let ret = null
while (ret = reg.exec('speak English')) {
    console.log(ret[0])
    console.log('lastIndex:' +reg.lastIndex)
}
//ret[0] -> e ret.index -> 2 reg.lastIndex -> 3
//ret[0] -> E ret.index -> 6 reg.lastIndex -> 7
  • string类型正则相关方法
  1. search(regexp)中第一个与 regexp 相匹配的子串的起始位置,如果没有找到则返回-1。该方法不执行全局匹配,它将忽略标志g。它同时忽略 regexp 的 lastIndex 属性,并且总是从字符串的开始进行检索,这意味着它总是返回 string 的第一个匹配的位置。
let ret = 'hello Jack'.search(/h/g) //返回2,g修饰符被忽略
let ret1 = 'hello Jack'.search(/b/g) //返回-1
  1. match(regexp) 匹配机制总体和exec()是相似的。
    如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。除了这些常规的数组元素之外,返回的数组还含有两个对象属性。index 属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。
    如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。若没有找到任何匹配的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。
let ret = 'hello Jack, hello Rose'.match(/hello/) // hello
let ret1 = 'hello Jack, hello Rose'.match(/hello/g) //[hello,hello] 
  1. replace(regexp,replacement)查找并替换的操作。它将在 stringObject 中查找与 regexp 相匹配的子字符串,然后用 replacement 来替换这些子串。如果 regexp 具有全局标志 g,那么 replace() 方法将替换所有匹配的子串。否则,它只替换第一个匹配子串。
let ret = 'hello Jack, hello Rose'.replace(/hello/g,'Hi') 
//Hi Jack, Hi Rose
let ret1 = 'hello Jack, hello Rose'.replace(/Jack/, 'Tom') 
//hello Tom, hello Rose
  1. split(separator,howmany) separator可以是正则表达式或者字符串,howmany限定数组长度。
    一个字符串数组。该数组是通过在 separator 指定的边界处将字符串 stringObject 分割成子串创建的。返回的数组中的字串不包括 separator 自身。
    但是,如果 separator 是包含子表达式的正则表达式,那么返回的数组中包括与这些子表达式匹配的字串(但不包括与整个正则表达式匹配的文本)。
    我们这里只讨论使用正则表达式的情况:
let ret = 'hello Jack, hello Rose'.split(/hello/g) 
//["", " Jack, ", " Rose"]
let ret1 = 'hello Jack, hello Rose'.split(/(hello)/) 
//["", "hello", " Jack, ", "hello", " Rose"]
常用实例
  • yyyy-MM-dd 时间格式校验 : /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/
  • 对数子进行千分位逗号隔开(如:12345678 123456789 -> 12,345,678 123,456,789) : /\B(?=(\d{3})+\b)/g
  • 国内手机号码校验:/^1[3456789]\d{9}$/
  • 大陆身份证号码校验:/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/
  • 邮箱校验: /^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$/
  • http地址校验: /^https?://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$/

结语

本篇主要针对正则基础的阐述,如果希望在熟练地应用到开发中还需要多多练习。

你可能感兴趣的:(JS正则表达式详解)