“Yeah It’s on. ”
正文
test
test() 方法用于检测一个字符串是否匹配某个模式.
RegExpObject.test(string)
string 必需。要检测的字符串。
返回值 如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false。
var str = "Visit W3School";
var patt1 = new RegExp("W3School");
var result = patt1.test(str);
document.write("Result: " + result);
replace
replace()
方法返回一个由替换值(replacement
)替换部分或所有的模式(pattern
)匹配项后的新字符串。模式可以是一个字符串或者一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。如果pattern
是字符串,则仅替换第一个匹配项。
var str = "我爱北京天安门,天安门上太阳升。";
var re = /北京|天安门/g; // 找到北京 或者天安门 全局匹配
var str2 = str.replace(re,'*');
alert(str2) //我爱**,*上太阳升
//这种只是把找到的变成了一个*,并不能几个字就对应几个*。
要想实现几个字对应几个*,我们可以用回调函数实现:
var str = "我爱北京天安门,天安门上太阳升。";
var re = /北京|天安门/g; // 找到北京 或者天安门 全局匹配
var str2 = str.replace(re,function(str){
alert(str); //用来测试:函数的第一个参数代表每次搜索到的符合正则的字符,所以第一次str指的是北京 第二次str是天安门 第三次str是天安门
var result = '';
for(var i=0;i<str.length;i++){
result += '*';
}
return result; //所以搜索到了几个字就返回几个*
});
alert(str2) //我爱*****,***上太阳升
//整个过程就是,找到北京,替换成了两个*,找到天安门替换成了3个*,找到天安门替换成3个*。
replace是一个很有用的方法,经常会用到。
: 或的意思。 |
语法
str.replace(regexp|substr, newSubStr|function)
参数
-
regexp
(pattern)一个
RegExp
对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。 -
substr
(pattern)一个将被
newSubStr
替换的字符串
。其被视为一整个字符串,而不是一个正则表达式。仅第一个匹配项会被替换。 -
newSubStr
(replacement) -
function
(replacement)一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。参考下面的指定一个函数作为参数。
使用字符串作为参数
替换字符串可以插入下面的特殊变量名:
| 变量名 | 代表的值 |
| —— | ———————————————————— |
| $$
| 插入一个 “$”。 |
| $&
| 插入匹配的子串。 |
| $
| 插入当前匹配的子串左边的内容。 |
|
$’ | 插入当前匹配的子串右边的内容。 |
|
$n | 假如第一个参数是 [
RegExp`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/RegExp)对象,并且 n 是个小于100的非负整数,那么插入第 n 个括号匹配的字符串。提示:索引是从1开始 |
指定一个函数作为参数
你可以指定一个函数作为第二个参数。在这种情况下,当匹配执行后,该函数就会执行。 函数的返回值作为替换字符串。 (注意:上面提到的特殊替换参数在这里不能被使用。) 另外要注意的是,如果第一个参数是正则表达式,并且其为全局匹配模式,那么这个方法将被多次调用,每次匹配都会被调用。
下面是该函数的参数:
变量名 | 代表的值 |
---|---|
match |
匹配的子串。(对应于上述的$&。) |
p1,p2, ... |
假如replace()方法的第一个参数是一个RegExp 对象,则代表第n个括号匹配的字符串。(对应于上述的$1,$2等。)例如,如果是用 /(\a+)(\b+)/ 这个来匹配,p1 就是匹配的 \a+ ,p2 就是匹配的 \b+ 。 |
offset |
匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 'abcd' ,匹配到的子字符串是 'bc' ,那么这个参数将会是 1) |
string |
被匹配的原字符串。 |
groups | 命名捕获组匹配的对象 |
举个例子:
template parser
let str = '<div> </div>';
let reg = /\{\{\s*(\S+)\s*\}\}/g;
let data = {
aaa: '我是aaa',
bbb: '我是bbbb',
};
const res = str.replace(reg, (match, p1, offset, string, groups) => {
if (p1) {
return data[p1];
}
});
console.log(111, res);
match
match() 在字符串中搜索复合规则的内容,搜索成功就返回内容,格式为数组,失败就返回null。
例子:找出指定格式的所有数字,如下找到 123,54,33,879
var str = 'haj123sdk54hask33dkhalsd879';
var re = /\d+/g;
// 每次匹配至少一个数字 且全局匹配 如果不是全局匹配,当找到数字123,它就会停止了。就只会弹出123.加上全局匹配,就会从开始到结束一直去搜索符合规则的。如果没有加号,匹配的结果就是1,2,3,5,4,3,3,8,7,9并不是我们想要的,有了加号,每次匹配的数字就是至少一个了。
alert( str.match(re) ); // [123,54,33,879]
match()
返回一个 数组 或 null
:
- 如果正则表达式没有找到匹配项,返回
null
。 - 如果找到了匹配项,返回一个数组,数组的第一个元素是匹配的完整字符串,后面的元素是所有捕获的分组(如果有的话)。
- 如果使用的是带有
g
(全局)标志的正则表达式,match()
会返回一个数组,包含所有的匹配字符串,而不会包含分组信息。
exec
与match方法不同exec属于正则表达式的方法。 语法:var result1 = regexp.exec(str); regexp:正则表达式(可以直接定义也可以利用RegExp的方式定义) str:要匹配的字串
当exec和match中具有相同的子表达式且为非全局匹配时两者的输出也是相同的
var str="visit W3cschool a W3cschool bull";
var reg=new RegExp("W3c(school)");
var b=reg.exec(str);
console.log(b);
console.log(str.match(/W3c(school)/));
执行上诉代码的结果为W3cschool,school
当为全局匹配时
var str="visit W3cschool a W3cschool bull";
var reg=new RegExp("W3cschool",'g');
var b=reg.exec(str);
console.log(b);
console.log(str.match(/W3cschool/g));
Exec中没有子表达式其输出为W3cschool,其输出只一个,match全局匹配时其输出元素中将包含所有的匹配项,其输出为W3cshcool,W3cschool
match和exec总结
全局标志(g
)的影响
- 对于带有全局标志
g
的正则表达式,match()
返回所有的匹配项(仅匹配字符串),不会返回捕获的分组信息。 - 对于带有全局标志
g
的正则表达式,exec()
每次调用会返回一个匹配项,并且它会保存“搜索位置”,使得每次调用时返回下一个匹配项。
捕获组的差异
- 如果没有全局标志,
match()
和exec()
都能返回捕获组(即正则表达式中括号()
中的内容)。 - 如果有全局标志,
match()
只返回匹配的字符串,不包含捕获组信息,而exec()
则会返回捕获组(如果有的话)。
对于单次匹配,match()
通常更方便;对于多次匹配,特别是带 g
标志时,exec()
提供了更多的控制。
const str = 'The quick brown fox';
const regex = /(\w+)\s(\w+)/;
// 返回一致
console.log(str.match(regex)); // ["The quick","The","quick"]
console.log(regex.exec(str)); // ["The quick","The","quick"]
const str = 'The quick brown fox';
const regex = /(\w+)\s(\w+)/g;
console.log(str.match(regex)); // ['The quick', 'brown fox']
let match = null;
while ((match = regex.exec(str)) != null) {
console.log(match[0]); // 匹配项
console.log(match[1]); // 匹配项中分组1
console.log(match[2]); // 匹配项中分组2
console.log('----------');
}
其他
命名分组
命名分组的语法是 (?<name>...)
,其中 <name>
是子表达式的名称。这样可以在正则表达式的其他地方通过 \k<name>
引用该子表达式的匹配结果。
const regex = /(?<content>\([^)]+\))/;
const text = "The content is (example).";
const match = text.match(regex);
console.log(match.groups); // { content: '(example)' }
console.log(match.groups.content); // '(example)'
console.log(match[0]); // '(example)'
正则中的字符
(),小括号,叫做分组符。就相当于数学里面的括号。如下: var str = ‘2013-6-7’; var re1 = /\d-+/g; // 全局匹配数字,横杠,横杠数量至少为1,匹配结果为: 3- 6- var re1 = /(\d-)+/g; // 全局匹配数字,横杠,数字和横杠整体数量至少为1 3-6- var re2 = /(\d+)(-)/g; // 全局匹配至少一个数字,匹配一个横杠 匹配结果:2013- 6-
var str = '2013-6-7';
var re = /(\d+)(-)/g;
str = str.replace(re,function($0,$1,$2){
//replace()中如果有子项,
//第一个参数:$0(匹配成功后的整体结果 2013- 6-),
// 第二个参数 : $1(匹配成功的第一个分组,这里指的是\d 2013, 6)
//第三个参数 : $1(匹配成功的第二个分组,这里指的是- - - )
return $1 + '.'; //分别返回2013. 6.
});
alert( str ); //2013.6.7
//整个过程就是利用子项把2013- 6- 分别替换成了2013. 6. 最终弹出2013.6.7
match方法也会返回自己的子项,如下:
var str = 'abc';
var re = /(a)(b)(c)/;
alert( str.match(re) ); //[abc,a,b,c]( 返回的是匹配结果 以及每个子项 当match不加g的时候才可以获取到子项的集合)
补充:exec()方法:和match方法一样,搜索符合规则的内容,并返回内容,格式为数组。 用法:正则.exec(字符串);
var testStr = "now test001 test002";
var re = /test(\d+)/; //只匹配一次
var r = "";
var r = re.exec(testStr)
alert(r);// test001 001 返回匹配结果,以及子项
alert(r.length); //2 返回内容的长度
alert(r.input); //now test001 test002 代表每次匹配成功的字符串
alert(r[0]); //test001
alert(r[1]); //001 代表每次匹配成功字符串中的第一个子项 (\d+)
alert(r.index ); // 4 每次匹配成功的字符串中的第一个字符的位置
[] : 表示某个集合中的任意一个,比如 [abc] 整体代表一个字符 匹配 a b c 中的任意一个,也可以是范围,[0-9] 范围必须从小到大。 [^a] 整体代表一个字符 :^写在[]里面的话,就代表排除的意思
例子:匹配HTML标签 比如<div class="b">hahahah </div>
找出标签
var re = /<[^>]+>/g; //匹配左括号 中间至少一个非右括号的内容(因为标签里面还有属性等一些东西),然后匹配右括号
var re = /<[\w\W]+>/g; //匹配左括号 中间至少一个字符或者非字符的内容,然后匹配右括号
// 其实就是找到左括号,然后中间可以有至少一个内容,一直到找到右括号就代表是一个标签。
转义字符
\s : 空格 \S : 非空格 \d : 数字 \D : 非数字 \w : 字符 ( 字母 ,数字,下划线_ ) \W : 非字符 .(点)——任意字符 . : 真正的点 \b : 独立的部分 ( 起始,结束,空格 ) \B : 非独立的部分
var str = 'onetwo';
var str2 ="one two";
var re = /one\b/; // e后面必须是独立的 可以是起始,空格,或结束
alert( re.test(str) ); //false
alert( re.test(str2) );//true
找重复项最多的字符个数
var str = 'assssjdssskssalsssdkjsssdss';
var arr = str.split(''); //把字符串转换为数组
str = arr.sort().join(''); //首先进行排序,这样结果会把相同的字符放在一起,然后再转换为字符串
//alert(str); // aaddjjkklsssssssssssssssss
var value = '';
var index = 0;
var re = /(\w)\1+/g; //匹配字符,且重复这个字符,重复次数至少一次。
str.replace(re,function($0,$1){
//alert($0); 代表每次匹配成功的结果 : aa dd jj kk l sssssssssssssssss
//alert($1); 代表每次匹配成功的第一个子项,也就是\w: a d j k l S
if(index<$0.length){ //如果index保存的值小于$0的长度就进行下面的操作
index = $0.length; // 这样index一直保存的就在最大的长度
value = $1; //value保存的是出现最多的这个字符
}
});
alert('最多的字符:'+value+',重复的次数:'+index); // s 17
量词
量词:代表出现的次数 {n,m}:至少出现n次,最多m次 {n,} :至少n次 *:任意次 相当于{0,} ?:零次或一次 相当于{0,1} +:一次或任意次相当于 {1,} {n}: 正好n次
//^ : 放在正则的最开始位置,就代表起始的意思,注意 /[^a] / 和 /^[a]/是不一样的,前者是排除的意思,后者是代表首位。
//$ : 正则的最后位置 , 就代表结束的意思
匹配中文的正则表达式
[\\u4e00-\\u9fa5]
.字符
. 特殊字符在中括号表达式时 如 [.] 只会匹配 .字符,等价于 \.,而非匹配除换行符 \n 外的所有字符。
var str = "runoob.com";
var patt1 = /[.]/;
document.write(str.match(patt1)); //输出 .
^ 和 ^指定字符串
- ^ 指的是匹配字符串开始的位置
- [^指定字符串] 指的是除指定字符串以外的其他字符串
(^[0-9])+ // 匹配有一至多个数字的字符串组合
[^[0-9]]+ // 匹配有一至多个不含数字的字符串组合
(?:)
https://segmentfault.com/q/1010000010302799
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
比较(X)和(?:X),前者是捕获分组,后者不捕获,区别在于正则表达式匹配输入字符串之后所获得的匹配的(数)组当中没有(?:X)匹配的部分;
var m = "abcabc".match(/(?:a)(b)(c)/)
//结果 ["abc", "b", "c"]
// m[0] 是/(?:a)(b)(c)/匹配到的整个字符串,这里包括了a
// m[1] 是捕获组1,即(b)匹配的子字符串substring or sub sequence
// m[2] 是捕获组2,即(c)匹配到的
?=X
”?=n” 匹配任何其后紧接指定字符串 n 的字符串
比如,你想匹配一个“人”字,但是你只想匹配中国人的人字,不想匹配法国人的人
就可以用一下表达式 (?=中国)人
(?=.*[a-z])\d+
这个就表示 匹配以“任意字符连着一个小写字母”开头的数字,只匹配数字。
而 (?<=exp)这个是放后面的。
(?:pattern)
非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在**使用或字符“( | )”来组合一个模式的各个部分是很有用**。例如“industr(?:y | ies)”就是一个比“industry | industries”更简略的表达式。 |
举个例子:
/\W|^(?:value|checked|selected|muted)$/
/\W|^value|checked|selected|muted$/
(?=pattern)
非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如,“Windows(?=95 | 98 | NT | 2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern)
非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如“Windows(?!95 | 98 | NT | 2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。 |
(?<=pattern)
非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95 | 98 | NT | 2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。 |
(?<!pattern)
非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95 | 98 | NT | 2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。这个地方不正确,有问题 |
懒惰限定符
代码/语法 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
\b
和\B
的区别
https://segmentfault.com/a/1190000013084624
\b
- 一个词的边界
匹配必须出现在 \w
(字母数字)和 \W
(非字母数字)字符之间的边界上。
\B
- 一个非单词边界
模式: /\Bend\w*\b/g
原字符串: `end sends endure lender`
匹配结果: `ends`和`ender`
常用的正则
// 空格
blank: /(^\s+)|(\s+$)/g,
// 注释
comment: /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm,
// 图片
images: /\.(jpeg|jpg|gif|png|webp)$/,
// url
url: /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i,
// media
media: /\.(jpeg|jpg|gif|png|webp|ico|mp3|mp4|oog|wav|eot|svg|ttf|woff|woff2|TTF|otf|OTF|json)$/,
tpl: /\.(html|php|vm)$/,
js: /\.js$/,
css: /\.css$/,
singleBraceInterpolate: /{([\s\S]+?)}/g,
doubleBraceInterpolate: //g,
htmlTag: /(<([^>]+)>)/ig,
require: /(?:(?:var|const)\s*(.*?)\s*=\s*)?require\(['"]([^'"]+)['"](?:, ['"]([^'"]+)['"])?\);?/g,
requireAsync: /require.async\(\[?((?:['"][^'"]+['"],?\s?)*)\]?\s?,\s?(?:function\s?\((.*)\))?/g,
useStrict: /(\/\/.*\r?\n)*['"]use strict['"];?/g
题目
获取on后面的字符串
let name = 'onXxx'
let res = name.match(/^on([\s\S]+)$/)
// ["onXxxxx", "Xxxxx", index: 0, input: "onXxxxx", groups: undefined]
console.log(RegExp.$1) // Xxx
有一个很重要的知识点是RegExp.$1
一道很好的题目
说明:给定一个编码字符,按编码规则进行解码,输出字符串,编码规则是cout[letter],将letter的内容count次输出,count是0或正整数,letter是区分大小写的纯字母。
示例: const s = ‘3[a]2[bc]’ 返回aaabcbc const s = ‘3[a2[c]]’ 返回accaccacc
function decodeString(str) {
let reg = /(\d+)\[(\w+)\]/g
str = str.replace(reg, (total, word1, word2) => {
return new Array(Number(word1)).fill(word2).join('')
})
return reg.test(str) ? decodeString(str) : str
}
let str = '3[a2[c]]'
console.log(decodeString(str)) //accaccacc
原理
正则表达式原理
正则表达式(Regular Expression,简称 regex)是一种用来描述文本模式的工具,可以在文本中进行复杂的查找、匹配、替换等操作。正则表达式的原理基于有限状态机、模式匹配和字符集等概念,下面我们将从 基本原理 和 常见概念 两个角度来理解正则表达式的工作原理。
基本原理:有限状态机(Finite State Machine, FSM)
正则表达式的工作机制本质上是通过构建一个 有限状态机 来扫描输入的文本。有限状态机是一种数学模型,具有以下特点:
- 状态:每个状态代表一个文本处理的阶段。
- 转移:根据当前的字符,状态机可以从一个状态转移到另一个状态。
- 接受状态:如果状态机扫描完输入文本并最终停留在一个特定的接受状态,就表示匹配成功。
简言之,正则表达式通过不断地扫描输入的字符,并根据字符和当前状态的规则进行状态转移。如果扫描完输入字符串后,状态机最终停留在一个接受状态,则表示输入字符串符合正则表达式的模式。