正则表达式学习笔记(一)基本语法

464 阅读6分钟

基本语法

语法: .

这个的作用是匹配任意字符。

语法:[]

定义一个字符的集合。

字符区间:在使用正则表达式的时候会频繁用到一些字符区间(09、AZ等)。为了简化字符区间的定义,正则表达式提供了一个特殊的元字符,-(连字符)来定义。连字符只能在[]中好用。定义字符区间的顺序一定要从小到大否则整个模式可能会失败。

语法:^

取非匹配。

^的效果将作用于给定字符集合里的所有字符或字符区间,而不是紧跟在^字符后面的那一个字符或字符区间。

例子:

[^A-Z] //将排除所有A-Z的集合
let  str='     </hahahahah</div id="name" class=haha  @on="click"  :value=\'value\''
//文本匹配需要考虑的是第一开头不能<或者</ 前面可以有空格
let  textReg=/\s*^[^<][^\/][^<]*/;

console.log(textReg.exec(str))

//这个例子的作用是^可以指定在某个匹配之后的开头必须是哪种模式

语法:+

匹配一个或者多个字符

[0-9]匹配任意单个字符,[0-9]+将匹配一个或多个连续的数字。(相当于做了一次循环判断,条件就是每个字符串是否满足0-9)

语法:?

正常字符后面表示1次或者0次匹配,元字符后面表示阻止贪婪匹配。

贪婪型元字符 + * {n,}

例子:

let  testReg=/(123){2,}/

console.log(testReg.test('123123123')) 

console.log('123123123'.match(testReg))  //匹配123123123

let  testReg=/(123){2,}?/

console.log(testReg.test('123123123')) 

console.log('123123123'.match(testReg))  //匹配123123

通过例子可以看出,贪婪模式是尽可能多的匹配符合条件的而懒惰型模式则是满足条件就停止。

let  testReg=/((123)|(456)){2,}/

console.log(testReg.test('123123123456')) 

console.log('123123123456'.match(testReg)) 
[ '123123123456',
  '456',
  undefined,
  '456',
  index: 0,
  input: '123123123456',
  groups: undefined ]

  //在贪婪模式下第一个匹配了结果满足条件之后还会继续找第二个(456)去匹配

  let  testReg=/((123)|(456)){2,}?/

console.log(testReg.test('123123123456')) 

console.log('123123123456'.match(testReg)) 

[ '123123',
  '123',
  '123',
  undefined,
  index: 0,
  input: '123123123456',
  groups: undefined ]

  //懒惰模式下 找到结果并且满足条件就不管第二个条件是否也有满足的了

语法:|

作用是或操作

let  attrReg=/([0-9a-zA-Z:@_\-]+)="([0-9a-zA-Z:@_\-]+)"|([0-9a-zA-Z:@_\-]+)/
//像这个或操作其实是或的([0-9a-zA-Z:@_\-]+)="([0-9a-zA-Z:@_\-]+)"和([0-9a-zA-Z:@_\-]+)
//如果不用()圈定或的范围(a|b)或就是|前后全部的表达式。
console.log(attrReg.exec(attrStr));
let attrStr = "id=\"hhah\" :id=\"name\" class=haha  @on=\"click\" "

let  attrReg=/([0-9a-zA-Z:@_\-]+)=\s*('([^''=\s]+)'|([^""''=\s]+)|"([^""=\s]+)")?/

console.log(attrReg.exec(attrStr));

[ 'id="hhah"',
  'id',
  '"hhah"',
  undefined,
  undefined,
  'hhah',
  index: 0,
  input: 'id="hhah" :id="name" class=haha  @on="click" ',
  groups: undefined ]

输出结果是从左到右从外到里面的顺序输出,所以字符串命中了|的最后一个也就是在数组第6的位置输出,前两个|为undefined因为没命中

子表达式

用来对正则表达式进行分组和归类。

正常来说元字符作用是只作用于自己紧挨的前一个字符比如如下:

let  testReg=/123{2,}/

console.log(testReg.test('123123123')) 

这段正则的作用是匹配两次以及以上的包含123的字符串,但是输出的却是false,这是因为元字符作用是只作用于自己紧挨的前一个字符,也就是实际上匹配的是 123333这样的。

那么我们如何让元字符作用于123之上呢?

这就是子表达式

用法是使用()包裹起来

let  testReg=/(123){2,}/

console.log(testReg.test('123123123')) //true

子表达式被看做一个独立元素,元字符作用于这个独立元素。

子表达式嵌套

()具有分组的功能,在match输出的结果中第一个是全部匹配的结果,第二个是分组的结果。如下:

let  testReg=/(123){2,}?/

console.log(testReg.test('123123123')) 

console.log('123123123'.match(testReg)) 
//输出
[ '123123',
  '123',
  index: 0,
  input: '123123123',
  groups: undefined ]

可以看到第一个是全部匹配的结果,第二个就是()内子表达式的匹配结果,因为这个子表达式本身的作用只是匹配123,所以只输出了123,那我们如何让全部匹配的结果输出在一个子表达式中呢?就是子表达式嵌套

let  testReg=/((123){2,}?)/

console.log(testReg.test('123123123')) 

console.log('123123123'.match(testReg)) 
[ '123123',
  '123123',
  '123',
  index: 0,
  input: '123123123',
  groups: undefined ]

输出结果是从全部再是从外到内来输出子表达式结果

回溯

回溯的作用就是使用前一个结果当做后一个的匹配


import\s*(\{?\s*[a-zA-Z0-9]+\s*\}?)\s*from\s*(('|")[a-zA-Z_./0-9]+?)\3

// \3的作用就是引用第3个子表达式
//[]内正则不需要转译

//输出模板 
const $1= requre ($2$3)

//$1代表第一个子表达式从外到里以此类推

前后查找

向前查找

向前查找指定了一个必须匹配但不在结果中返回的模式。

从语法上看,向前查找就是一个以?=开头的子表达式(?=需要匹配的文本),需要匹配的文本跟在=后面。
//处理文件名称
const fileReg=/([^/]*)(?=\.)\.([a-zA-Z]+)([^.]*)/

console.log(fileReg.exec('6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.image?t=45425'))

[ '6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.image?t=45425',
  '6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1',
  'image',
  '?t=45425',
  index: 0,
  input: '6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.image?t=45425',
  groups: undefined ]

位置匹配具有贪婪性,一定要匹配到最后的一个匹配之前的才可以,比如以上的输出就是在最后一个.之前的

以上通过位置匹配的贪婪性向前查找拿到了除后缀之外的内容,再通过不将位置“.”分组拿到了后缀名称,通过分组+位置匹配解决了文件名字的处理

向后查找

//处理文件名称
const fileReg=/([^/]*)(?<=\.)([a-zA-Z]+)([^.]*)/

console.log(fileReg.exec('6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.image?t=45425'))

[ '6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.image?t=45425',
  '6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.',
  'image',
  '?t=45425',
  index: 0,
  input: '6bda613994324068ac.76f9ccd80e64d1~tplv-k3u1fbpfcp-zoom-1.image?t=45425',
  groups: undefined ]

位置匹配具有贪婪性,一定要匹配到最后的一个匹配之前的才可以,比如以上的输出就是在最后一个.之后的

嵌入条件

正则表达式里的条件

?匹配前一个字符或表达式,如果存在的话

?=和?<=匹配前面和后面的文本,如果它存在的话。

嵌入条件语法也使用了?

根据一个回溯引用来进行条件处理。

根据一个前后查找来进行条件处理。

回溯引用条件

回溯引用条件只在一个前面的(子表达式)搜索取的成功的情况下才允许使用一个表达式。

定义:(?(backreference)true-regex) 其中?表明这是一个条件,backreference是一个回溯引用,true-regex在backreference存在时才会被执行的子表达式。

实战

解析一段html

标签开头粗解析

html标签分为两种,完整闭合和自闭合,所以在解析中需要注意。

1、一个标签的开头应该是<>或者</>,正则表达式如下:

let  startTag=/^<\/?>/ //^表示匹配开头  ?的作用表示0次或者一次
console.log(startTag.test('</>')) //true
console.log(startTag.test('1<>')) //false
console.log(startTag.test('<>')) //true

2、一个html标签开头应该是 a-z和A-Z之间的字母

let  startTag=/^<[a-zA-Z]\/?>/
console.log(startTag.test('<1>')) //false
console.log(startTag.test('<a>')) //true
console.log(startTag.test('<A>')) //true

3、剩下的可以是数字或者字母也可以没有

let  startTag=/^<[a-zA-Z][a-zA-Z0-9]*\/?>/
console.log(startTag.test('<1>')) //false
console.log(startTag.test('<a>')) //true
console.log(startTag.test('<A1>')) //true

4、因为一个标签可能还存在属性一大堆,属性需要考虑 @ — _ : 字母数字等

let  startTag=/^<[a-zA-Z][a-zA-Z0-9]+[0-9a-zA-Z=""\s:@_\-]*?\/?>/

console.log(startTag.test('<Hahaha name="haha" name=haha name @name="hahaha" class="j_l j-l"/>'))  //true

元字符后加?是预防可能存在的贪婪匹配

5、解析一个标签不可能一个表达式全搞定在这里我们需要将标签名和属性分为两组,属性暂且全部获取到再另行处理,而<>则抛弃