Skip to content

Latest commit

 

History

History
256 lines (195 loc) · 6.31 KB

03正则表达式括号的作用.md

File metadata and controls

256 lines (195 loc) · 6.31 KB

正则表达式括号的作用

分组和分支结构

这二者表示的是括号最原始的功能,强调括号内的正则是一个整体,即提供子表达式

  1. 分组:/a+/ 匹配连续出现的 a,而要匹配连续出现的 ab 时,需要使用 /(ab)+/

    let regx = /(ab)+/g
    let str = "ababa abbb"
    console.log(str.match(regx))
    //[ 'abab', 'ab' ]
  2. 分支结构:多选分支结构 (p1|p2),提供分支表达式的所有可能

    let reg = /^I love (you|myself)$/
    console.log(reg.test("I love you"))//true
    console.log(reg.test("I love myself"))//true

分组引用

使用分组引用可以进行数据提取,以及替换操作

let reg = \(\d{4})-(\d{2})-(\d{2})\
  • 使用了分组引用,会出现如(Groud #1)这样的分组编号
  • 正则引擎在匹配过程中,会给每一个分组都开辟一个空间,用来存储每一个分组匹配到的数据

提取数据、年、月、日

let reg = /(\d{4})-(\d{2})-(\d{2})/
let str = '1234-12-12'
console.log(str.match(reg))
// [
//   '1234-12-12',
//   '1234',
//   '12',
//   '12',
//   index: 0,
//   input: '1234-12-12  2020-02-02',
//   groups: undefined
// ]
  • match 返回一个数组,第一个元素时整体匹配的结果,然后是各个分组(括号里)匹配的内容,然后匹配下标,最后是输入文本

    • 如果使用 g 修饰符,match 返回的数据格式不一样
  • 使用正则实例对象 exec

let reg = /(\d{4})-(\d{2})-(\d{2})/
let str = '1234-12-12'
console.log(reg.exec(str))
// [
//   '1234-12-12',
//   '1234',
//   '12',
//   '12',
//   index: 0,
//   input: '1234-12-12',
//   groups: undefined
// ]
  • 使用构造函数的全局属性 $1~$9
let reg = /(\d{4})-(\d{2})-(\d{2})/
let str = '1234-12-12'

reg.test(str)
console.log(RegExp.$1)//1234
console.log(RegExp.$2)//12
console.log(RegExp.$3)//12

yyyy-mm-dd 格式替换成 mm/dd/yyyy

let reg = /(\d{4})-(\d{2})-(\d{2})/
let str = '1234-12-12'
let result = str.replace(reg, "$2/$3/$1")
console.log(result)//12/12/1234
  • 等价于一下这两种
let result = str.replace(reg, function () {
  return `${RegExp.$2}/${RegExp.$3}/${RegExp.$1}`
})
//第二种
// let result = str.replace(reg, function (match, year, month, day) {
//   return `${month}/${day}/${year}`
// })

反向引用

除了相应 API 引用分组,也可以在正则本身里引用分组。但只能引用之前的分组,即反向分组

  • 例如需要正则匹配如下三种格式
2012-12-12
2012/12/12
2012.12.12
  • 例如写成如下的正则,不仅匹配了要求的情况,还匹配了 1234-12/12 这种情况
const regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/;
let str = '1234-12/12'
console.log(regex.test(str))//true
  • 如果使用反向引用可以解决这样的问题
const regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
let str = '1234-12/12'
console.log(regex.test(str))//false
  • 这里的 \1 表示的引用之前的那个分组 (-|\/|\.) 不管匹配到什么,比如(-)、\1 都匹配到那个同样的字符
  • \2\3...就代表第二个和第三个分组...

括号嵌套:会以左括号的开括号位准

const regex = /((\d)(\d(\d)))\1\2\3\4/
const string = "1231231233"
console.log( regex.test(string) ) // true
console.log( RegExp.$1 ) // 123
console.log( RegExp.$2 ) // 1
console.log( RegExp.$3 ) // 23
console.log( RegExp.$4 ) // 3
  1. $1 匹配的是 ((\d)(\d(\d)))
  2. $2 匹配的是 (\d)
  3. $3 匹配的是 (\d(\d))
  4. $4 匹配的是 (\d)
  • \1 表示的是第一个分组的内容,第一个开括号对应的分组是 123

  • \2 表示的时第二个分组的内容,第二个开括号对应的分组是 1

  • \3 表示的时第三个分组的内容,第三个开括号对应的分组是 23

  • \3 表示的时第四个分组的内容,第四个开括号对应的分组是 3

\10:第十个分组不是 \10

let reg = /(1)(2)(3)(4)(5)(6)(7)(8)(9)(#) \10+/
let str = "123456789# ####"
console.log(reg.test(str))//true
  • 如果需要匹配 \1 和 0,需要使用 (?:\1)0 或者 \1(?:0)

引用不存在的分组,正则不会报错,而是反向引用的字符本身。

  • 例如 \2 就匹配 \2,表示对 2 进行转义的意思
let reg = /\1\2/
let str = "\1\2"
console.log(reg.test(str))//true

分组后有量词

  • 如果分组后有量词,分组最终捕获到的数据是最后一次的匹配,(\d)-->5
let reg = /(\d)+/
let str = "12345"
console.log(str.match(reg))
//[ '12345', '5', index: 0, input: '12345', groups: undefined ]
  • 对于反向引用也是这样
let reg = /(\d)+ \1/
let str1 = "12345 5"
let str2 = "12345 1"

console.log(reg.test(str1))//true
console.log(reg.test(str2))//false

非捕获括号:之前文章出现的括号,都会捕获他们匹配到的数据,以便后续使用,因此称之为是捕获型分组和捕获型分支

  • 如果只想要括号最原始的功能,而不引用它,即即不再 API 中引用也不在正则里的反向引用

  • 此时可以使用非捕获括号 (?:p)(?:p1|p2|p3)

    let regx = /(?:ab)+/g
    let str = "ababa abbb"
    console.log(str.match(regx))
    //[ 'abab', 'ab' ]

案例

  1. 字符串 trim 方法

    function trim(str) {
      //return str.replace(/^\s*|\s*$/g, "")  
      return str.replace(/^\s*(.*?)\s*$/g, "$1")
    }
  2. 将每个单词的首字母转化为大写

    function titleize(str) {
      return str.toLowerCase().replace(/(?:^|\s)\w/g, function (c) {
        return c.toUpperCase()
      })
    }
  3. 驼峰化

    function camelize(str) {
      return str.replace(/[-_\s]+(.)?/g, function (match, c) {
        return c ? c.toUpperCase() : ""
      })
    }
    • 其中分组 (.) 表示首字母。单词的界定是,前面的界定是,前面可以是多个 -_ 或者 \s
    • 使用 ? 是为了防止 str 的尾部可能不是单词字符,例如 "-moz-transform "
  4. 中划线化

    function dashsize(str) {
      return str.replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
    }