《正则表达式必知必会》笔记

698 阅读5分钟

正则表达式必知必会

单字符匹配

  • 全局匹配 g

  • 忽略大小写 i

  • . 表示匹配任意单个字符

  • \ 转义字符:正则中patten的特殊字符都是有特殊含义的,如果想单纯表明是一个字符,则需要要使用 \ 进行转义.

  • - 连字符通常只出现在 []区间中,[]之外的连字符只能与它本身匹配(没有特殊意义),所以不需要转义

const reg = /.\./ig;
const text = 'n.1.'

console.log(reg.exec(text));

回溯引用

  • 回溯引用允许使用正则表达式使用 上次匹配的结果
// \1表示第一个子表达式匹配到的结果
const reg = /[ ]+(\w+)[ ]+\1/
const text = ` off off of
`
console.log(text.match(reg));
// 匹配合法的html标签
const reg = /\<([hH][1-6])\>.*\<\/\1\>/g
const text = `
<h3>hahha</h3>

<h2>hahha</h2>

<h3>haha</h4>
`
console.log(text.match(reg));
  • \1 表示引用第一个子表达式的匹配结果 ,\2表示引用第二个子表达式的匹配结果 。。。。
const reg = /\<([hH][1-6])\>(.*?)\<\/\1\>\2/g
const text = `
<h3>aa</h3>aa

<h2>hahha</h2>

<h3>haha</h4>
`
console.log(text.match(reg));
  • 回溯引用替换字符串
// 给字符串添加 h1标签
const reg = /(\w+)(\n)/g
const text = `
haha

xixi
`
console.log(text.replace(reg,`<h1>$1</h1>$2$2`));

// 转换tel格式
const reg = /(\d{3})-(\d{3})-(\d{3})/g
const text = `313-555-234`
console.log(text.replace(reg,'($1) $2-$3'));

// 首字母大写

const reg = /(^[a-zA-F])([a-zA-F]+)/g
const text = `babel`
console.log(text.replace(reg,(...args)=>{
    return args[1].toUpperCase() + args[2]
}));

const reg = /(^[a-zA-F])([a-zA-F]+)/g
const text = `babel`
console.log(text.replace(reg,(...args)=>{
    return args[1].toUpperCase() + args[2]
}));

匹配一组字符

  • 元字符[] 定义一个字符集合,字符集合的匹配结果 是能够与该集合里的任意一个成员相匹配的文本。
const reg = /[Rr]eg/;
const text = 'Reg'

console.log(reg.exec(text));
  • 字符集合之间的 + , . ,/ 将被解析为普通字符,即不需要进行转义
/[+.]/ // +
  • 字符集合区间
  1. /[A-z]/ : [,^ 等在ASCII字符表里排列在 Z和 a之间的字符也会被匹配
/[0-9]/ // 0123456789
/[A-z]/ // 不常用
/[A-Z]/ // A B C D .... Z
/[a-zA-Z0-9]/ // 匹配a-z A-Z 0-9中的任意一个字符
  • 元字符^ 取非匹配
  1. /[^A-z]/ : 匹配不在区间 A-z的字符

  2. /[^a-z0-9]/ : 是作用于 整个字符集合 而不是 ^后面的某个区间

const reg = /[^A-z]/;
const text = '1'
console.log(reg.exec(text)); //match

const reg = /[^a-z0-9]/;
const text = '9'

console.log(reg.exec(text)); //null
  • demo: 匹配RGB值

RGB:一个十六进制数字给出的组合值

const reg = /#[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]/;
const text = '#FFF333  #CCCCCC'
console.log(reg.exec(text));
const reg = /[^a-z0-9]/;
const text = '9'

console.log(reg.exec(text)); //not match

匹配重复的次数

  • {n} : 匹配 {}之前的字符 n次
const reg = /#[0-9A-Fa-f]{6}/
const text = '#ffffff'
console.log(reg.exec(text)); 
  • {min,max} : 匹配 {}之前的字符 min次到max次

  • {min,} : 匹配 {}之前的字符 至少min

  • *+贪婪形的元字符,在贪婪形字符的后面添加 ? 表示其 懒惰形版本

const reg = /[a]+?/
const text = 'aaa'
console.log(reg.exec(text)); // 只能匹配到一个a

get

  1. 如果需要匹配 / ,尽量使用 \/ 进行匹配

  2. 贪婪形的行为模式是多多益善,而不是适可而止. 多多益善表现为一直从一段文本的开始一直匹配到这段文本的结尾,适可而止表现为从这段文本的开始一直匹配到第一个匹配时为止

const reg = /[a]+?/
const text = 'aaa'
console.log(reg.exec(text)); 

前后查找

  • : 向前查找模式 以 ?= 开头的子表达式 , 需要匹配的文本跟在 =后面
// ?=:表示 匹配 : 但是匹配结果 不消费 这个 :
const reg = /.+(?=:)/g // /.+(:)/g :匹配结果将消费这个:
const text = `
https://www.baidu.com
http://www.tencent.com
`

console.log(text.match(reg));
  • : 向后查找模式 以 ?<=开头的子表达式
// 匹配$后面所有的数子
const reg = /(?<=\$)[\d\.]+/g
const text = `
apple: $10
peer: $16
banna: $xxx
`
console.log(text.match(reg));
  • :匹配html标签直接的内容
// 外层包裹的子表达式不会成为 回溯引用的结果
const reg = /(?<=<(\w+)>).*(?=<\/\1>)/g
const text = `
<h1>标签</h1>
<h3>not match</h2>
<span>xxxx</span>
`
console.log(text.match(reg));

// console.log(text.replace(reg,'$1'));
  • :负向前匹配和负向后匹配 将 = 换成 !
const reg = /\b(?<!中国)[a-zA-Z]+\b/g
const text = `中国china city`
console.log(text.match(reg));// city
const reg = /\b(?<=中国)[a-zA-Z]+\b/g
const text = `中国china city`
console.log(text.match(reg));// china

嵌入条件

js 不支持嵌入条件

  • (?(回溯引用)true-reg|false-reg)

  • (?(回溯引用)true-reg)

const reg = /(<a>)?<li>.*<\/li>(?(1)<\/a>|<\/b>)/
const text = `
<li>哈哈</li>
<a><li>呜呜</li></a>
`

使用元字符

  • \ 转义字符 : 一个完整的正则表达式,字符 \ 的后面永远跟着另一个字符

  • 匹配空白字符 : \f , \n , \r ...

  • 字符类: 匹配某一个类别的字符 。

/\d/ === /[0-9]/
/\D/ === /[^0-9]/

/\w/ === /[a-zA-Z0-9_]/
/\W/ === /[^a-zA-Z0-9_]/

/\s/ 
/\S/

get

  1. linux: 文本行结束标签 \n
const reg = /\w/g
const text =`123w`
console.log(reg.exec(text)); 

使用子表达式

可用于对表达式进行分组和归类

  • (exp):子表达式必须使用 () 进行包裹
const reg = /(age){2,}/
const text = 'ageage' // match
console.log(reg.exec(text));

// 匹配ip地址
const reg = /(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))/
const text = '11.255.11.11'
console.log(reg.exec(text));
  • |:正则表达式中的或操作符
// 20\d{2}是一个匹配 19是一个匹配
const reg = /19|20\d{2}/

// 匹配年份

const reg = /[20|19]\d{2}/
const text = '2021'
console.log(reg.exec(text));

const reg = /(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))/
const text = '11.255.11.11'
console.log(reg.exec(text));

位置匹配

边界限定符: 限定匹配操作在什么位置发生

  • [x]: 单词边界: \b 匹配单词的边界 , \B 匹配单词的非边界
// 匹配所有的英文单词
const reg = /\b[a-zA-Z]{1,}\b/g;
const text = '中 cat 哈哈 dog'
console.dir(text.match(reg));

// 匹配前后不是单词边界的连字符
const reg = /\B-\B/g;
const text = 'a - a'
console.dir(text.match(reg));
  • [x]: 字符串边界: ^ 以什么开头 , $ 以什么结尾
const reg =/\<[\w+]{1,}\>(.*)\<\/[\w+]\>/g;
const text = `
<p> hello </p>
<p> world </p>
`
console.dir(text.match(reg));
const reg =/\<[\w+]\s*[\w='"]{0,}\>(.*)\<\/[\w+]\>/g;
const text = `
<p name="123123"> hello </p>
<p> world </p>
`
console.dir(text.match(reg));

重复匹配

  • +:匹配一次或者多次特定的字符
const reg = /a+/;
const text = 'aa';
console.log(reg.exec(text)); // 匹配到两个a
// 匹配邮箱
const reg = /\w+@\w+\.com/;
const text = '656603135@qq.com';
console.log(reg.exec(text)); 
// 匹配二级域名
const reg = /[\w.]+@[\w.]+\.\w+/;
const text = '656603135@qq.cn.com';
console.log(reg.exec(text)); 
  • *:匹配零次或者多次特定的字符,即字符是可选的
// 匹配已字符开头的字符串
const reg = /\w+[\w.]*@[\w.]+\.\w+/;
const text = 'a@qq.cn.com';
console.log(reg.exec(text)); 
  • ?:匹配零次或者一次特定的字符
// https和 http都可以匹配 []提高可读性
const reg = /http[s]?:\/\/[\w./]+/;
const text = 'https://baidu.com/';
console.log(reg.exec(text)); 
// 删除所有的空格 兼容window和linux
const reg = /[\r]?\n[\r]?\n/g;
const text = `asda

asd

asdasd

asdasd
`;
console.log(text.replace(reg,'\n')); 
const reg = /[\r]?\n[\r]?\n/g;
const text = `asda

asd

asdasd

asdasd
`;
console.log(text.replace(reg,'\n'));