正则表达式

330 阅读3分钟

原文 前端之巅 公众号的精选文章,感谢作者分享。 正则表达式真的很6,可惜你不会写

1、元字符

元字符 基本说明
. 匹配除换行符以外的任意字符
\w 匹配非特殊符号,即匹配字母/数字/下划线/汉字
\s 匹配任意的空白符
\d 匹配数字
^ 匹配字符串的开始
$ 匹配字符串的结束

2、重复限定符

语法 基本说明
* 重复0次或多次
+ 重复1次或多次
重复0次或1次
{n} 重复n次
{n,} 重复n次或以上
{n,m} 重复n次到m次

3、分组

语法 基本用法
() ^(ab)*

4、转义

语法 基本用法
\ ^(\(ab\))* --->转义()

5、条件或

语法 基本用法
| ('你'|'我')

6、区间

语法 基本用法
[] [0-4]

7、零宽断言

1)正向先行断言(正前瞻)

语法:(?=pattern)
作用:匹配 pattern 表达式的前面内容,不返回本身。-->前

'<span class="read-count">阅读数:641</span>'.match(/\d+(?=\<\/span\>)/)
// ["641"]

2)正向后行断言(正后顾)

语法:(?<=pattern)
作用:匹配 pattern 表达式的后面的内容,不返回本身。后<--

'<span class="read-count">阅读数:641</span>'.match(/(?<=\<span class="read-count"\>阅读数:)\d+/)
// ["641"]

3)负向先行断言(负前瞻)

语法:(?!pattern)
作用:匹配非 pattern 表达式的前面内容,不返回本身。 -->前 左到右

有正向也有负向,负向在这里其实就是非的意思。 举个栗子:比如有一句 “我爱祖国,我是祖国的花朵” 现在要找到不是'的花朵'前面的祖国

'我是祖国的花朵,我爱我的祖国'.match(/祖国(?!的花朵)/)
//["祖国"]

4)负向后行断言(负后顾)

语法:(?<!pattern)
作用:匹配非 pattern 表达式的后面内容,不返回本身。 后<--

(?<=)和(?<!) —JavaScript不支持

8、 捕获和非捕获

单纯说到捕获,他的意思是匹配表达式,但捕获通常和分组联系在一起,也就是“捕获组”。

捕获组:匹配子表达式的内容,把匹配结果保存到内存中中数字编号或显示命名的组里,以深度优先进行编号,之后可以通过序号或名称来使用这些匹配结果。

根据命名分为数字编号捕获组和命名编号捕获组

1)数字编号捕获组

第0组是整一个表达式,第一组开始为分组

var number = '020-85653333'
var arr=  /(0\d{2})-(\d{8})/.exec(number)
console.log(arr)
//["020-85653333", "020", "85653333", index: 0, input: "020-85653333", groups: undefined]

//另一种获取值,test()、exec()、以及String的正则方式执行完都可以
console.log(RegExp.$1) //'020' 第一个分组的值
console.log(RegExp.$2) //'world' 第二个分组的值

//这里的$1$2与方法二里的RegExp.$1、RegExp.$2作用是相同的。
var n_number = number.replace( /(0\d{2})-(\d{8})/,"$2 $1");
console.log(n_number) //"85653333 020"

2)命名编号捕获组

语法(?<name>exp),取个别名

var number = '020-85653333'
var arr=  /(?<quhao>0\d{2})-(?<haoma>\d{8})/.exec(number)
console.log(arr)
//["020-85653333", "020", "85653333", index: 0, input: "020-85653333", groups: {quhao: "020", haoma: "85653333"}]
//这里可以通过groups获取值

3)非捕获组

语法:(?:exp),简单来说就是不进行保存的捕获组

var number = '020-85653333'
var arr=  /(?:0\d{2})-(\d{8})/.exec(number)
console.log(arr)
//["020-85653333", "85653333", index: 0, input: "020-85653333", groups: undefined]
//这里 020就没有保存

9、反向引用

捕获会返回一个捕获组,这个分组是保存在内存中,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。

根据捕获组的命名规则,反向引用可分为:

  • 数字编号组反向引用:\k 或\number
  • 命名编号组反向引用:\k 或者'name'

捕获组通常是和反向引用一起使用的,捕获组是匹配子表达式的内容按序号或者命名保存起来以便使用。

//查找一串字母"aabbbbgbddesddfiid"里成对的字母
var str = 'aabbbbgbddesddfiid';
console.log(str.match(/(\w)\1/g));
// ["aa", "bb", "bb", "dd", "dd", "ii"]

// 把字符串 abcbbabcbcgbddesddfiid 中 abc 换成 a
var str = 'abcbbabcbcgbddesddfiid'
console.log(str.replace(/(a)bc/g,'$1'))
//abbabcgbddesddfiid

10、贪婪和非贪婪

贪婪

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,这匹配方式叫做贪婪匹配。

特性:一次性读入整个字符串进行匹配,每当不匹配就舍弃最右边一个字符,继续匹配,依次匹配和舍弃(这种匹配 - 舍弃的方式也叫做回溯),直到匹配成功或者把整个字符串舍弃完为止,因此它是一种最大化的数据返回,能多不会少。

前面的【重复限定符】就是贪婪量词:

const str = '61762828 176 2991 44 871';
console.log(str.match(/\d{3,6}/g)); // ["617628", "176", "2991", "871"]
const str = '61762828 176 2991 87321';
console.log(str.match(/(\d{1,2})(\d{3,4})/g)); // ["617628", "2991", "87321"]

非贪婪匹配

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能少的字符,这匹配方式叫做懒惰匹配。

特性:从左到右,从字符串的最左边开始匹配,每次试图不读入字符匹配,匹配成功,则完成匹配,否则读入一个字符再匹配,依此循环(读入字符、匹配)直到匹配成功或者把字符串的字符匹配完为止。

懒惰量词是在贪婪量词后面加个“?”

  • *? 重复任意次,但尽可能少重复
  • +? 重复1次或更多次,但尽可能少重复
  • ?? 重复0次或1次,但尽可能少重复
  • {n,m}? 重复n到m次,但尽可能少重复
  • {n,}? 重复n次以上,但尽可能少重复

/(\d{1,2}?)(\d{3,4})/

11、 反义

元字符的都是要匹配什么什么,当然如果你想反着来,不想匹配某些字符,正则也提供了一些常用的反义元字符:

元字符 解释
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符