正则表达式

正则表达式

正则表达式是用来匹配字符串的一种模式。
做的一次分享,记录一下

规则:

最先匹配上的优先,例

'1wer123s'.replace(/1/,'')	//"wer123s"

主要参考

  1. 以前学js记的笔记
  2. https://www.w3school.com.cn/jsref/jsref_obj_regexp.asp
  3. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

工具型网站

图解正则

正则大全:现成正则,平时写正则不多的,直接用这个也够了

在线正则验证

创建

let reg = /abc/;

let reg = new RegExp("abc");

特殊字符(需要转义的字符)

普通字符包括:字母(abcABC),数字(123),_等等

特殊字符:() [] {} ^ $ * ? \ | + . 需要用\转义

let reg = /\$/;
let str = '15$';
reg.test(str);	//true

修饰符g i m

放在正则//后面

  • g 表示全局匹配
  • i 忽略大小写
  • m 多行匹配
let reg = /1/g;
let str = '1516';
str.split(reg);	// ["", "5", "6"]

分界符^ $ ?= ?!

  • ^ 以某字符开头

  • $ 已某字符结尾

    let reg = /^1/;
    let str = '16+19';
    reg.test(str);	// true
    
字符含义
^n以n开头
n$以n结尾

分组()和|或

|表示或,如果分组中没有|,就必须匹配分组内完整的字符串

let reg = /^(1|2)/;	
let str = '22$15';
reg.test(str);	//true

let reg = /^(12)/;	
let str = '22$15';
reg.test(str);	// false

当正则有使用分组时,可以通过RegExp. 1 取 正 则 对 应 分 组 的 内 容 , 1取正则对应分组的内容, 1后跟的数字表示是匹配的正则中第几个分组。

let reg = /^(1)\d*(9)$/;	
let str = '1345789';
reg.test(str);	//true
RegExp.$1 	// '1'
RegExp.$2	// '9'

非捕获括号?:

(?:x)

匹配 ‘x’ 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。

捕获

let reg = /^(1)\d*(9)$/;	
let str = '1345789';
reg.exec(str);	// ['1345789', '1', '9', index: 0, input: '1345789', groups: undefined]
reg.test(str);	// true
RegExp.$1 	// '1'
RegExp.$2	// '9'

非捕获

let reg = /^(?:1)\d*(9)$/;	
let str = '1345789';
reg.exec(str);	// ['1345789', '9', index: 0, input: '1345789', groups: undefined]
reg.test(str);	// true
RegExp.$1 	// '9',
RegExp.$2	// ''

断言

来自MDN

模式含义
x(?=y)x后紧跟y, 匹配’x’仅仅当’x’后面跟着’y’.这种叫做先行断言。 例如,/Jack(?=Sprat)/会匹配到’Jack’仅当它后面跟着’Sprat’。/Jack(?=Sprat|Frost)/匹配‘Jack’仅当它后面跟着’Sprat’或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。
(?<=y)`xx前紧跟y, 匹配’x’仅当’x’前面是’y’.这种叫做后行断言。 例如,/(?<=Jack)Sprat/会匹配到’ Sprat ‘仅仅当它前面是’ Jack '。/(?<=Jack|Tom)Sprat/匹配‘ Sprat ’仅仅当它前面是’Jack’或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。
x(?!y)x后不跟y, 仅仅当’x’后面不跟着’y’时匹配’x’,这被称为正向否定查找。 例如,仅仅当这个数字后面没有跟小数点的时候,/\d+(?!.)/ 匹配一个数字。正则表达式/\d+(?!.)/.exec(“3.141”)匹配‘141’而不是‘3.141’
(?<!y)xx前不跟y, 仅仅当’x’前面不是’y’时匹配’x’,这被称为反向否定查找。 例如, 仅仅当这个数字前面没有负号的时候,/(?<!-)\d+/ 匹配一个数字。 /(?<!-)\d+/.exec('3') 匹配到 “3”. /(?<!-)\d+/.exec('-3') 因为这个数字前有负号,所以没有匹配到。
let str = 'foofoo';
let reg1 = /foo{2,3}/;
let reg2 =  /(?:foo){2,3}/;
reg1.test(str);	// false
reg2.test(str);	// true

先行断言(前瞻)

符号含义
x(?=y)x其后紧跟 y
x(?!y)x后不跟y
let str="Is this all there is";
let reg=/is(?= all)/g;
reg.test(str) // true

let str="Is this all there is";
let reg=/is(?=all)/g;
reg.test(str) // false

后发断言(后顾)

符号含义
(?<=y)xx前紧跟y
(?<!y)xx前不跟y

量词? * + {}

符号出现次数(x)
?0 || 1 {0,1}
*x>=0 {0,}
+x>=1 {1,}
{n}0 || n
{n,m}n<= x <=m (中间不能有空格)
{n,}x >= n
let reg = /\$+/;
let str = '15$16$$';
str.split(reg);	// ["15", "16", ""]

模式

参考较多

性能优化探究影响性能的因素NFA自动机的回溯

正则表达式的回溯方式

正则表达式三种模式:贪婪模式、懒惰模式、独占模式

js正则表达式引擎、贪婪与懒惰

注意:

1、同贪婪模式一样,独占模式一样会匹配最长。不过在独占模式下,正则表达式尽可能长地去匹配字符串,一旦匹配不成功就会结束匹配而不会回溯,可用于性能优化

2、js不支持独占模式,会报错

贪婪(量词)懒惰(?)独占(+)
X?X??X?+
X*X*?X*+
X+X+?X++
X{n}X{n}?X{n}+
X{n,}X{n,}?X{n,}+
X{n,m}X{n,m}?X{n,m}+
贪婪模式(最长匹配).+ , .*

1、量词默认贪婪模式(会先匹配最长的,匹配不上再回溯,往前推。所以量词要避免嵌套否则会导致指数级回溯)

let reg = /b{1,3}/;
let str = 'aaabbc';
str.match(reg) // ['bb', index: 3, input: 'aaabbc', groups: undefined]

2、/a.*b/表示匹配a到b的最长字符串

let reg = /a.*b/;
let str = '15a$a16b$b$bc';
str.split(reg);	// ["15", "c"]
str.replace(reg, '-');	//'15-c'
懒惰模式(最短匹配).+? , .*?

1、量词后加?,变成懒惰模式

let reg = /b{1,3}?/;
let str = 'abbc';
reg.test(str)	//true

let reg = /b{1,3}?/;	// 懒惰
let str = 'aaabbc';
str.match(reg)	// 先匹配最短['b', index: 3, input: 'aaabbc', groups: undefined]

let reg = /b{1,3}/;	// 贪婪
let str = 'aaabbbc';
str.match(reg)	// 先匹配最长['bbb', index: 3, input: 'aaabbbc', groups: undefined]

2、/a.*?b/表示匹配a到b的最短字符串

let reg = /a.*?b/;
let str = '15a$a16b$b$bc';
str.split(reg);	// ["15", "$b$bc"]

字符集[]

只要符合集合中的一项即可

基础

let reg = /[a13kc]/;	
let str = '12$15';
reg.test(str);	//true

范围字符集

常用

  • [a-z] 小写子母集合,也可以从中间开始取[b-d]表示bcd
  • [A-Z] 大写子母集合
  • [0-9] 数字集合

特殊含义字符

^非

[^123] 表示不包含1的字符集

\b退格符

[\b]表示退格符(非元字符的单词边界)

注意:

除了 \,-,^, ] 之外的非字母数字字符在字符类中都没有特殊含义,不需要转义

组合拼接[0-9]

常用

[a-zA-Z] 子母集合

[\u4e00-\u9fa5] 中文集合 (汉字Unicode编码

元字符(Metacharacter)

特殊字符(换行等)\t \n \f …

***注意:***空格符没有特殊字符,直接输入空格即可

let reg = / /g;
let str = `a b`;
reg.test(str);	// true

let reg = / /g;
let str = `ab`;
reg.test(str);	// false

符号含义
\t制表符
\n换行符
\f换页符
\r回车符
\0NUL 字符
\v垂直制表符
\xxx以八进制数 xxx 规定的字符
\xdd查找以十六进制数 dd 规定的字符。
\uxxxx以十六进制数 xxxx 规定的 Unicode 字符
let reg = /\n/;
let str = `a
b`;
reg.test(str);	// true

类 (特殊字符集缩写). \d \s \w …

字符集含义
.[^\n\r]非换行、回车符
\d[0-9]数字
\D[^0-9]非数字
\s[ \t\n\x0B\f\r]空白(\x0B表示垂直tab,无法书写),含空格
\S[^ \t\n\x0B\f\r]非空白
\w[a-zA-Z_0-9]单词字符(字母数字下划线)
\W[^a-zA-Z_0-9]非单词
\b-单词边界(单词字符的边界)例:2a+3b=5c,边界就是2a,3b,5c左右两边的位置
\B-非单词边界,如上的例子,非单词边界就是2和a,3和b,5和c之间的位置
let reg = /\d/;
let str = '15$';
reg.test(str);	//true
let str = 'm13';
let reg1 = /\bm1/;	// \b放左就表示匹配字符m1其左边是边界
let reg2 = /m1\b/;	// \b放右就表示匹配字符m1其右边是边界
str.match(reg);
reg1.test(str); 	// true,
reg2.test(str); 	//false,

性能

参考

正则也是存在性能问题的,某些优化不好的正则会不断回溯,占用cpu很长时间去匹配,影响页面效果。

改进:避免回溯

console.time('start');
console.log(/(A+A+)+B/.exec('AAAAAAAAAA'));	// 量词嵌套导致回溯
console.timeEnd('end')

image-20210930111111195

1、在使用量词匹配时尽量使用[最长](#贪婪模式(最长匹配).+ , .*)或[最短](#懒惰模式(最短匹配).+? , .*?)匹配

js正则相关方法

传入方法的数字一般会匹配去对应的字符串

RegExp 对象方法

test

含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false。

RegExpObject.test(string)

exec

详解:w3c

索字符串中的正则表达式的匹配。返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。

RegExpObject.exec(string)
/\d/.exec('21ssfr')
["2", index: 0, input: "21ssfr", groups: undefined]

注意:

此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject的第 2 个子表达式相匹配的文本(如果有的话),以此类推

即返回的只有第0个元素才是完全匹配的文本,后面两个都只是子表达式(括号中的分组捕获)匹配的结果,具体案例见文章最后vue3源码正则-获取当前tag

compile

w3c例子

egExpObject.compile(regexp,modifier)
参数描述
regexp正则表达式。
modifier规定匹配的类型。“g” 用于全局匹配,“i” 用于区分大小写,“gi” 用于全局区分大小写的匹配。
var str="Every man in the world! Every woman on earth!";

patt=/man/g;
str2=str.replace(patt,"person");
document.write(str2+"<br />");	// Every person in the world! Every woperson on earth!

patt=/(wo)?man/g;
patt.compile(patt);
str2=str.replace(patt,"person"); 	// Every person in the world! Every person on earth!
document.write(str2);

String 对象方法

search

w3c

stringObject.search(regexp|string)	

返回值

stringObject 中第一个与 regexp 相匹配的子串的起始位置。

注释:如果没有找到任何匹配的子串,则返回 -1。

说明

search() 方法不执行全局匹配,它将忽略标志 g。它同时忽略 regexp 的 lastIndex 属性,并且总是从字符串的开始进行检索,这意味着它总是返回 stringObject 的第一个匹配的位置

let str = '11te3st123'
let reg = /1/;
str.search(reg);	// 0

match

match() 方法可在字符串内检索指定的值,或找到一个或多个(正则有无全局匹配g标识)正则表达式的匹配。

该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。

stringObject.match(string | regexp)

let str = 'test123';
let reg = /^test/;
str.match(reg);		// ["test", index: 0, input: "test123", groups: undefined]

let searchStr = 'st';
str.match(searchStr);	// ["st", index: 2, input: "test123", groups: undefined]

let str = '11te3st123';
let reg = /1/g;
str.match(reg); // ["1", "1", "1"]

replace

https://www.w3school.com.cn/jsref/jsref_replace.asp

replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

stringObject.replace(regexp/substr,replacement)

replacement: 字符串或函数

特殊字符$:

字符替换文本
$1、$2、…、$99与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。
$&与 regexp 相匹配的子串。
$`位于匹配子串左侧的文本。
$’位于匹配子串右侧的文本。
$$直接量符号。
let reg = /(\w+)\+(\w+)/;
let str = 'a+b';
str.replace(reg, '$2, $1'); // "b, a"
console.log(RegExp.$1); // "a"
console.log(RegExp.$2); // "b"

split

split() 方法用于把一个字符串分割成字符串数组。

stringObject.split(string|reg,howmany)

howmany: 可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。

let str = '11te3st123';
let reg = /1/
str.split(reg, 3);	//  ["", "", "te3st"].length <= 3

正则案例

网址邮箱来自正则大全,自己阅读解析可以根据图解正则

电话:

/^1[3-9]\d{9}$/

网址:

/^((ht|f)tps?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?$/

邮箱:

/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

问题:用正则怎么解析类似vue的模板变量

举个栗子,实际源码不是这样解析的

let str = '嗨,您好,今天是星期 {{ day.value }}';
let reg = /\{\{.+?\}\}/;
reg.test(str);
let str = '嗨,您好,今天是星期 {{ day.value }},天气{{ day.weather }}';
let reg = /\{\{.+?\}\}/g;

let arr = str.match(reg); // ['{{ day.value }}', '{{ day.weather }}']
arr.map(a => a.replaceAll(/[\{\}\s]/g, ''))	// ['day.value', 'day.weather']

网址:

/^((ht|f)tps?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?$/

邮箱:

/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

问题:用正则怎么解析类似vue的模板变量

举个栗子,实际源码不是这样解析的

let str = '嗨,您好,今天是星期 {{ day.value }}';
let reg = /\{\{.+?\}\}/;
reg.test(str);
let str = '嗨,您好,今天是星期 {{ day.value }},天气{{ day.weather }}';
let reg = /\{\{.+?\}\}/g;

let arr = str.match(reg); // ['{{ day.value }}', '{{ day.weather }}']
arr.map(a => a.replaceAll(/[\{\}\s]/g, ''))	// ['day.value', 'day.weather']
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值