Go to comments

JavaScript 正则 下

W3C 手册

一、量词

量词很简单是代表数量的词

量词描述
n+匹配任何包含至少一个 n 的字符串。
n*匹配任何包含零个或多个 n 的字符串。
n?匹配任何包含零个或一个 n 的字符串。
n{X}匹配包含 X 个 n 的序列的字符串。
n{X,Y}匹配包含 X 至 Y 个 n 的序列的字符串。
n{X,}匹配包含至少 X 个 n 的序列的字符串。
n$匹配任何结尾为 n 的字符串。
^n匹配任何开头为 n 的字符串。
?=n匹配任何其后紧接指定字符串 n 的字符串。
?!n匹配任何其后没有紧接指定字符串 n 的字符串。



n+

n是个变量,n可以代表任何东西,

+加号代表这个变量n可以重复出现一次到无数次

也就是说n现在的区间是 {1, Infinity} 1到正无穷,Infinity正无穷就不写了,写一个逗号这样 {1,  } 


/\w+/

加号的意思是前面这个变量\w,可以出现一次到多次,也就是说这个\w可以重复出现无数次(多少次都可以)

下面的正则表达式能不能匹配成功?可以匹配成功返回["abc"],相当于\w出现了三次

var reg = /\w+/g;

var str = "abc";

console.log(str.match(reg)); // ["abc"]


n*

区间是0到正无穷 {0, Infinity} 


 /\w*/

星号意思是可以出现0次到多次,下面能匹配出来吗?肯定能匹配出来返回["abc", ""]

var reg = /\w*/g;

var str = "abc";

console.log(str.match(reg));// ["abc", ""]


匹配出两个["abc", ""] ,一个是abc、后面还加了一个空串"",匹配出来一个空是什么意思?

1). 它匹配的时候非常智能,先看"abc"符合要求,符合要求算一个

2). 然后还有修饰符g意思是全局匹配,现在光标在c后面,c后面还有一段距离叫逻辑上的距离,什么是逻辑上的距离?

3). /\w*/  如果*变成0的话,那匹配就是空了,然后在c后面的逻辑点上又往后匹配出一个空出来

4). 一开始*变成abc,第二次再匹配*变成零了,换句话说正则表达式匹配出一个空出来


再看 /\d*/ 能匹配出字符串"abc"出结果吗?能,匹配出四个空["", "", "", ""]

var reg = /\d*/g;

var str = "abc";

console.log(str.match(reg));// ["", "", "", ""]

匹配出四个结果都是空,那是逻辑上光标依次往右去移动,

1). 第一次光标在第一个a前面的时候是0,所以把a前面匹配出来了,

2). a匹配不了,然后到a后面去,a后面还是一个0,在乘个0还是一个空,所以有多少个光标定位点就有多少个空。


上面的 /\w*/ 怎么没匹配那么多空呢?

一旦\w能识别出值,它会先看a能识别、b能识别、c能识别,它会先一连串的把这些能识别的识别了,到最后的时候才试一下乘0,原则是能匹配多就不匹配少


比如下面字符串是一排"aaaaaaaaaa",正则 /\w+/g 能把这一排a全匹配出来返回["aaaaaaaaaa"]

var reg = /\w+/g;

var str = "aaaaaaaaaa";

console.log(str.match(reg)); // ["aaaaaaaaaa"]

为什么不一个一个匹配?

因为正则的原则就是能多就不少,正则表达式有个原则叫“贪婪匹配原则”能多就不少(能四个尽量就不三个)


n? 

也是一个量词,能取的值0到1个 {0, 1} 

下面的匹配的是多少个?能把所有的a都取出来["a", "a", "a", "a", "a", "a", "a", "a", "a", "a", ""]但最后还要加一个空串,因为到最后的时候,后面没有a了加一个空。

var reg = /\w?/g;

var str = "aaaaaaaaaa";

console.log(str.match(reg));// ["a", "a", "a", "a", "a", "a", "a", "a", "a", "a", ""]


n{X}

意思是x个,把这个区间定死了


 /\w{3}/g 填3就是3个,3个的匹配返回 ["aaa", "aaa", "aaa"]

var reg = /\w{3}/g;

var str = "aaaaaaaaaa"; // 字符串有10个a

console.log(str.match(reg));//  ["aaa", "aaa", "aaa"]


n{X, Y}

还可以填区间意思是x到y个


 /\w{3,5}/g  3个到5个

1). 首先符合匹配原则,能5个就别3个4个,实在5个不了了,再试试3个行不行

2). 字符串有18个a,匹配结果 ["aaaaa", "aaaaa", "aaaaa", "aaa"] 前面三组5个a最后一组3个a

var reg = /\w{3,5}/g;

var str = "aaaaaaaaaaaaaaaaaa"; // 字符串有18个a

console.log(str.match(reg)); // ["aaaaa", "aaaaa", "aaaaa", "aaa"]


如果字符串是19个a呢?还是贪婪匹配原则能四个就不三个

var reg = /\w{3,5}/g;

var str = "aaaaaaaaaaaaaaaaaaa";

console.log(str.match(reg)); //["aaaaa", "aaaaa", "aaaaa", "aaaa"]


这个 n{X, Y} 区间还可以填的更奔放一点,后面的y可以不写,不写的意思是Ifinity,x到正无穷{x, Ifinity},

可以自定义1到正无穷 {1, },1到正无穷就是1到不写,1到不写就和+号没区别


1到不写 和 +号,一样全给匹配出来

var str = "aaaaaaaaaaaaaaaaaaa";


var reg = /\w{1,}/g; // 1到正无穷{1, }
console.log(str.match(reg));//["aaaaaaaaaaaaaaaaaaa"]


var reg = /\w+/g; // "+号"1到多个
console.log(str.match(reg));//["aaaaaaaaaaaaaaaaaaa"]


{1, }   1到不写和+号没区别

{0, }   0到不写和*号没区别

{2, }   2到正无穷和3到正无穷是我们可以定义的


量词很简单,但是记住量词它"量"的是什么?

n乘以这个量词,也就是 \w 乘以这个量词,不是 \w 的结果乘以这个量词,一定得记住。

如果 \w的结果 乘以这个量词,那匹配出来的东西必须都是一致的,要是a后面全得跟着a,ab都不行。


意思是字符串"abcde",通过 /\w{2,}/g 能匹配出来吗?能匹配出来,量词"量"的是\w,是\w乘很多东西,然后每一位\w在随机匹配,而不是\w先匹配一个结果再乘量词

var reg = /\w{2,}/g;

var str = "abcde";

console.log(str.match(reg)); // ["abcded"]


通过量词匹配,保证不了每一位都相同,只能保证每位都取自同一个区间

var reg = /a{1,2}/g;
var str = "aaaaabcde";
console.log(str.match(reg));//["aa", "aa", "a"]



var reg = /a{2,}/g;
var str = "aaaaabcde";
console.log(str.match(reg));//["aaaaa"]



var reg = /a{2,}/g;
var str = "aa";
console.log(str.match(reg)); // ["aa"]



var reg = /a{2,}/g;
var str = "a";
console.log(str.match(reg)); // null



var reg = /a{1,}/g;
var str = "aaaa";
console.log(str.match(reg)); // ["aaaa"]



var reg = /a{2,3}/g;
var str = "aaaaaaaaaa";
console.log(str.match(reg)); // ["aaa", "aaa", "aaa"] 十个a只匹配出三组九个



var reg = /a{1,3}/g;
var str = "aaaaaaaaaa";
console.log(str.match(reg)); // ["aaa", "aaa", "aaa", "a"] 十个a匹配出三组零一个


下面 n$ 和 ^n,一个匹配结束,一个匹配开头跟量词没关系,不能算是量词里面的


^n

匹配任何开头为 n 的字符串


正则 /abc/g 能匹配字符串"abcded"出来吗?能匹配出来,字符串里面有abc的片段。

var reg = /abc/g;

var str = "abcded";

console.log(str.match(reg)); // ["abc"]

 

/^abc/g 现在有一个要求匹配以abc开头的,可以这么理解开头的a后面必须跟着bc,这样的abc能匹配出来吗?也可以匹配出

var reg = /^abc/g;

var str = "abcded";

console.log(str.match(reg)); // ["abc"]


n$

匹配任何结尾为 n 的字符串


/abcd$/g  以abcd结尾能匹配出来吗?匹配不出来了

var reg = /abcd$/g;

var str = "abcded";

console.log(str.match(reg)); // ["null"]


/ed$/g  以ed结尾呢?能匹配出来返回["ed"]

var reg = /ed$/g;

var str = "abcded";

console.log(str.match(reg)); // ["ed"]


$符号写在后面,就是以什么什么结尾,$符号会受修饰符m的影响,可以多行匹配。


问一个问题

下面以abc开头,以abc结尾能匹配成功吗?

var reg = /^abc$/g;

var str = "abcadc";

console.log(str.match(reg)); // ["null"]


不能匹配成功,这么理解以当前abc开头,还得以当前这个abc结尾,必须开头结尾是同一套,这样一个开头一个结尾就能起到一个作用,把这个字符串限定死,这个字符串必须得是abc,

一个开头一个结尾能达到限定字符串的作用,限定字符串的长度,有开头有结尾就把字符串固定住了。


只有字符串"abc"是最搭配的

var reg = /^abc$/g;

var str = "abc";

console.log(str.match(reg)); // ["abc"]


正则面试题

写一个正则表达式,检验字符串首尾是否含有数字?

这题的重点不在写,重点在于能否读懂,首尾是否含有数字什么意思?

是首有、尾也得有,还是首有就行或者尾有就行?

首尾是否含有数字?中华文化博大精深,“首尾是否含有”没有说首尾含有,没有说字,所以首尾含所有数字的意思是首有就行、尾有也行。

var reg = /^\d|\d$/g; // 开头是数字或或结尾是数字

var str = "123abc";

console.log(str.match(reg)); // ["1"]

console.log(reg.test(str)); // true


如果首或尾“都”含有数字怎么写? 

var reg = /^\d[\s\S]*\d$/g; // 小s大S代表任何东西,*号出现0到多个,中间拿一个区间拉伸

var str = "123abc456";

console.log(str.match(reg)); // ["123abc456"]

console.log(reg.test(str)); // true


附:之前学PHP时候说  (.*)  是一个经典的用法

var reg = /^\d(.*)\d$/g;

var str = "123abc456";

console.log(str.match(reg)); // ["123abc456"]

console.log(reg.test(str));// true


二、RegExp 对象属性

属性描述FFIE
globalRegExp 对象是否具有标志 g。14
ignoreCaseRegExp 对象是否具有标志 i。14
lastIndex一个整数,标示开始下一次匹配的字符位置。14
multilineRegExp 对象是否具有标志 m。14
source正则表达式的源文本。14


属性什么意思呢?

正则表达式是一个对象,对象上势必会有些属性的。


ignoreCase属性

reg.ignoreCase返回false,证明上面没写修饰符i,如果写了i就返回true

var reg = /^\d[\s\S]*\d$/g;

console.log(reg.ignoreCase); // false


global属性

现在写了修饰符g,reg.global返回ture

var reg = /^\d[\s\S]*\d$/g;

console.log(reg.global); // ture


multiline属性(多行)

没有写修饰符m多行,reg.multiline返回false

var reg = /^\d[\s\S]*\d$/g;

console.log(reg.multiline); // false


source属性

source属性代表里正则表达式里面的体,写的内容能给显示出来,用字符串来展示出来。

var reg = /^\d[\s\S]*\d$/g;

console.log(reg.source); // ^\d[\s\S]*\d$


以上这些属性都无关紧要,有一个属性是最有用的就是lastIndex,这个属性要到下面 exec方法 时候再说


W3C 手册


三、RegExp 对象方法

方法描述FFIE
compile编译正则表达式。14
exec检索字符串中指定的值。返回找到的值,并确定其位置。14
test检索字符串中指定的值。返回 true 或 false。14


正则表达式的test()方法里面填一个字符串,来检验能不能符合要求,符合要求返回true不符合要求false,但是功能太局限了

有一个NB的方法exec()(exec读"一刻再课",执行的意思)也是一个匹配方法,这个方法是本篇重点。


exec()方法非常有意思,下面写一个例子

var reg = /ab/g;

var str = "abababab"; // 字符串有四个"ab"


console.log(reg.exec(str)); // ["ab", index: 0, input: "abababab", groups: undefined]

console.log(reg.exec(str)); // ["ab", index: 2, input: "abababab", groups: undefined]

console.log(reg.exec(str)); // ["ab", index: 4, input: "abababab", groups: undefined]

console.log(reg.exec(str)); // ["ab", index: 6, input: "abababab", groups: undefined]

console.log(reg.exec(str)); // null

console.log(reg.exec(str)); // ["ab", index: 0, input: "abababab", groups: undefined]

执行四次reg.exec(str)匹配成功,第五次执行输出null,再执行它依然这样的循环


第一次执行返回的信息

var reg = /ab/g;

var str = "abababab";

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]

这是返回的信息 ["ab", index: 0, input: "abababab", groups: undefined]

第一个是"ab"是匹配的一个体,index是0,最后返回input,返回的是类数组

index是索引的意思,也就是说这个游标在字符串的哪个位置匹配的,ab在第0个位置(abababab)所以index是0


下一次再执行reg.exec(str)

正则有g修饰符号,注意有g和没g不一样,有g修饰符再执行一次,结果是index: 2变了,2是"abababab"匹配的是红色ab的位置是2,第一次匹配的是第一组ab,第二次是在第一次的基础上接着匹配的

var reg = /ab/g;

var str = "abababab";

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 2, input: "abababab", groups: undefined]


再执行两次,index的值分别是0、2、4、6,字符串的游标"0ab2ab4ab6ab"

var reg = /ab/g;

var str = "abababab";

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 2, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 4, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 6, input: "abababab", groups: undefined]


第四次匹配之后,游标到"abababab游标位置"红色文字这里,再匹配一次能匹配到吗?再匹配一边之后发现打印的是null

var reg = /ab/g;

var str = "abababab";

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 2, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 4, input: "abababab", groups: undefined]

console.log(reg.exec(str));// ["ab", index: 6, input: "abababab", groups: undefined]

console.log(reg.exec(str));// null


如果再匹配呢?返回到第一次匹配的了,就好像这个游标在一圈一圈的轮圈的转

var reg = /ab/g;

var str = "abababab";

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]
console.log(reg.exec(str));// ["ab", index: 2, input: "abababab", groups: undefined]
console.log(reg.exec(str));// ["ab", index: 4, input: "abababab", groups: undefined]
console.log(reg.exec(str));// ["ab", index: 6, input: "abababab", groups: undefined]
console.log(reg.exec(str));// null

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]
console.log(reg.exec(str));// ["ab", index: 2, input: "abababab", groups: undefined]
console.log(reg.exec(str));// ["ab", index: 4, input: "abababab", groups: undefined]
console.log(reg.exec(str));// ["ab", index: 6, input: "abababab", groups: undefined]
console.log(reg.exec(str));// null


而这个游标到底有没有呢?

有,这个游标的属性就是reg.lastIndex


这个lastIndex和exec方法是相协调匹配的,lastIndex就是为了exec方法而存在的,它就是游标

var reg = /ab/g;

var str = "abababab";


// 第一次匹配
console.log(reg.lastIndex);// 0
console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]

// 第二次匹配
console.log(reg.lastIndex);// 2
console.log(reg.exec(str));// ["ab", index: 2, input: "abababab", groups: undefined]

// 第三次匹配
console.log(reg.lastIndex);// 4
console.log(reg.exec(str));// ["ab", index: 4, input: "abababab", groups: undefined]

// 第四次匹配
console.log(reg.lastIndex);// 6
console.log(reg.exec(str));// ["ab", index: 6, input: "abababab", groups: undefined]


exec方法通过找游标的位置,来进行下一次匹配,

第一次游标的位置是0,然后会在游标的位置向后匹配,匹配到下一个为止,它会把lastIndex这个游标放到第二位上,再匹配会在lastIndex的基础上,去往后再匹配依次去变,

游标的变化是lastIndex的变化,每匹配一次后结束的位置就是下一次lastIndex开始的位置,最后匹配一圈后又归零了。


如果每次把 lastIndex 手动修改一下呢?

var reg = /ab/g;

var str = "abababab";

console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]


console.log(reg.lastIndex); // 1. 第一次匹配完后“lastIndex”应该是2


reg.lastIndex = 0; // 2. 现在lastIndex再变回0


console.log(reg.exec(str)); // 3. 再匹配一次index还是0 ["ab", index: 0, input: "abababab", groups: undefined] 


console.log(reg.lastIndex); // 现在再匹配lastIndex是2,它还是正常往后移动的

手动把游标给挪回0之后,下一次index还是从第0位匹配,从哪里开始匹配是完全由lastIndex来控制


如果不加全局修饰符g会发生什么样的变化呢?发现lastIndex根本就不移动,永远从第一位匹配,匹配不了后面的

var reg = /ab/;

var str = "abababab";


console.log(reg.lastIndex);// 0
console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]


console.log(reg.lastIndex);// 0
console.log(reg.exec(str));// ["ab", index: 0, input: "abababab", groups: undefined]

往下要拓展点小知识"子表达式"


四、子表达式

想匹配一个字符串类似于这样"xxxx"的形式,凡是这样的形式都符合要求,这是一个公式不是说四个aaaa就行了、四个bbbb也行、四个zzzz也行,只要四个是一样的就行


var str = "aaaa";   这样的形式

var reg = //;         怎么写这个正则表达式的匹配?


这个 (a) 括号还有一个意思叫做 子表达式 ,算表达式的一种,正常来说这个子表达式写上括号也没什么用也不影响,

但是在特殊情况下,当用括号把这个表达式括起来之后,这个括号会记录里面匹配的内容,然后记录完之后我们会反向引用出来

var str = "aaaa"; 

var reg = /(a)\1/g // 这个的"反斜杆1"的意思叫"反向引用"第一个子表达式里面匹配的内容(第一个括号里面的东西叫第一个子表达式),所以现在它匹配的是a和后面同样的a

console.log(str.match(reg)); // ["aa", "aa"]


上面的比较简单,下面把子表达式里面换成元字符\w,就变成了\w匹配出来的东西,后面要Copy出一个一模一样的,叫反向引用第一个子表达式里面匹配的内容

var str = "aaaa"; 

var reg = /(\w)\1/g

console.log(str.match(reg)); // ["aa", "aa"]


后面加三个\1,就是三次"反向引用"第一个子表达式里面匹配的内容,匹配出来["aaaa"]

var str = "aaaa"; 

var reg = /(\w)\1\1\1/g; 

console.log(str.match(reg));// ["aaaa"]


如果字符串换成"aaaabbbb"能匹配出两个["aaaa", "bbbb"]

var str = "aaaabbbb";

var reg = /(\w)\1\1\1/g;

console.log(str.match(reg));//  ["aaaa", "bbbb"]


下面用同样的规则,能匹配出"aabb"吗?不能匹配返回null,反向引用的是第一个子表达式里面匹配出的内容,也就是说后面的必须跟前面的完全雷同

var str = "aabb";

var reg = /(\w)\1\1\1/g;

console.log(str.match(reg));// null


想要匹配"aabb"这样的形式怎么写?\1是反向引用第一个子表达式里面的内容,依次类推第二个子表达式是\2

var str = "aabb";

var reg = /(\w)\1(\w)\2/g; // 反向引用第一个子表达式,反向引用第二个子表达式,保障前两个相等后两个相等

console.log(str.match(reg)); // ["aabb"]


接下了还得看正则的exec方法

var str = "aabb";

var reg = /(\w)\1(\w)\2/g; 

console.log(reg.exec(str)); // ["aabb", "a", "b", index: 0, input: "aabb", groups: undefined]

数组里多出了两位"a", "b"是第一个子表达式匹配的内容和第二个子表达式匹配的内容

而且多出来的两位是正式的"数据位",什么是数据位?是挂在数组里面的索引位上的,虽然是类数组但是类数组里的正规军能当数组使。


不加通配符g也是这个样子的,只是不变lastindex而已

var str = "aabb";

var reg = /(\w)\1(\w)\2/; 

console.log(reg.exec(str)); //  ["aabb", "a", "b", index: 0, input: "aabb", groups: undefined]

这个exec()方法在jQuery源码里还有,而且是是深度应用


W3C 手册


五、支持正则表达式的String对象的方法

方法描述FFIE
search检索与正则表达式相匹配的值。14
match找到一个或多个正则表达式的匹配。14
replace替换与正则表达式匹配的子串。14
split把字符串分割为字符串数组。14


match是字符串的方法,也可以填字符串,但是一般都填正则表达式,按照正则表达式的规则,匹配字符串里面有多少个片段,不加g只匹配出一个片段(要么没有要么一个),然后返回的结果类似有exec,把第一个子表达式和第二个子表达式引用的内容也出来了

var str = "aabb";

var reg = /(\w)\1(\w)\2/; 

console.log(str.match(reg)); // ["aabb", "a", "b", index: 0, input: "aabb", groups: undefined]


但是一旦加修饰符g后,就不在有那些累赘信息了,加g后之只是把匹配多少个返回,什么子表达式全没有了

var str = "aabb";

var reg = /(\w)\1(\w)\2/g; 

console.log(str.match(reg)); // ["aabb"]


search方法查找的,是匹配到的这个片段的位置,但凡返回的不是"-1"的都匹配成功了

var str = "aabb";

var reg = /(\w)\1(\w)\2/g; 

console.log(str.search(reg)); // 0


"edbaabb"在字符串开头增加edb三个字母,返回匹配到片段的位置是 3

var str = "edbaabb";

var reg = /(\w)\1(\w)\2/g; 

console.log(str.search(reg));// 3


字符串结尾再加几个字母"cdfaabbbbee"会有变化吗?没有变化返回的还是3,search方法和exec方法不一样,它只是返回匹配的位置,不返回匹配了多少个,加不加g没区别

var str = "cdfaabbbbee";

var reg = /(\w)\1(\w)\2/g; 

console.log(str.search(reg)); // 3

// console.log(reg.exec(str)); //  ["aabb", "a", "b", index: 3, input: "cdfaabbbbee", groups: undefined]


如果匹配不到返回-1,位置没有负一,所以负一代表错误信息

var str = "abc";

var reg = /(\w)\1(\w)\2/g; 

console.log(str.search(reg)); // -1


split()方法是拆分字符串,里面可以填字符串还可以填正则表达式,按正则表达式去拆

var str = "dada1AAwc3nvBBad4CCdsdf";

var reg = /(\w)\1/g; // 如果有两个重复的字符就拆了(大写的字母都是重复的)

console.log(str.split(reg)); //  ["dada1", "A", "wc3nv", "B", "ad4", "C", "dsdf"]

上面写子表达式,把子表达式放到了返回信息里面


不用子表达式,用数字拆分

var str = "dada1AAwc2nvBBad3CCdsdf";

var reg = /\d/g; // 按数字拆字符串

console.log(str.split(reg)); // ["dada", "AAwc", "nvBBad", "CCdsdf"]


replace方法最后一个是最重要,最实用的字符串方法

先看正常的replace的用法,不用正则表达式写,字符串里面的a替换成b,返回结果是"ba",replace没有访问全局的能力只能访问一个,这是没有用正则表达式的缺陷

var str = "aa";

console.log(str.replace("a" ,"b")); // ba


但是如果用正则表达式就两说了,现在匹配多少个?还是改变1个,因为没加修饰符g

var reg = /a/;

var str = "aa";

console.log(str.replace(reg ,"b")); // ba


写上修饰符g就全变了返回bb

var reg = /a/g;

var str = "aa";

console.log(str.replace(reg ,"b")); // bb


replace方法的精华在于正则表达式上


精华到什么程度呢?把"aabb"的形式倒过来,变成"bbaa"怎么做?

var reg = /(\w)\1(\w)\2/g; // 首先把aa bb匹配出来

var str = "aabb"; 

newStr = str.replace(reg ,"$2$2$1$1");


// 1.替换的部分一定要写成字符串
// 2.子表达式的内容,replace()参数这里能反向引用到
// 3.怎么引用?用$来引用
// 4.$1代表第一个字表达式内容,$2代表第二个子表达式内容
// 5.$2$2$1$1返回bbaa


console.log(newStr); // bbaa


还有一种更高大上的替换方式

str.replace(reg ,"$2$2$1$1") 参数不是关注字符串吗,这块不写字符串写个function函数(replace(reg, function)),但是function处理完要返回一个字符串,

可以利用function处理这个返回的字符串,有function就变的更灵活了,function不归我们调用系统会帮我们调用,系统会传参数我们得接收。


function($, $1, $2) 系统传得第一个参数是正则表达式匹配的全局,或者说是正则表达式匹配的结果,然后第二个参数是第一个子表达式匹配的内容,第三个参数是第二个子表达式匹配的内容

var reg = /(\w)\1(\w)\2/g;

var str = "aabb";

console.log(str.replace(reg ,function($, $1, $2){

     return $2 + $2 + $1 + $1; // bbaa

}));


甚至可以再疯狂一点再加字符串"abc"可以随便拼,有了这样的function之后就变的灵活多了

var reg = /(\w)\1(\w)\2/g;

var str = "aabb";

console.log(str.replace(reg ,function($, $1, $2){

    return $2 + $1 + $2 + $1 + '---abc'; // baba---abc

}));


现在看一个字符串方法

字符串有个方法是toUpperCase()字母变大写,toLowerCase字母变小写

var str = "aabb";

console.log(str.toUpperCase()); // AABB

console.log(str.toUpperCase().toLowerCase()); // aabb


看一道非常有意思的题

字符串“the-first-name”经过处理之后变成小驼峰式写法“theFirstName”

先找规律-f是规律,把 "-f"变F,-n变成N

1) 先匹配-f  "/-\w/g"

2) 匹配到"-f"替换"f",怎么把"f"单独找出来?有一个办法,$引用的是子表达式,把\w括号起来。

3). 替换成下滑线看看,返回 the_irst_ame

var reg = /-(\w)/g;

var str = "the-first-name";

console.log(str.replace(reg, "_")); // -f、-n先替换成下划线 "the_irst_ame"

现在怎么变大写的F,用function第一个参数是$,用第二个参数$2

var reg = /-(\w)/g;

var str = "the-first-name";

console.log(str.replace(reg, function($ ,$1){
    return $1.toUpperCase(); // theFirstName
}));

这是正则表达式一个高级的用法。

匹配了多少次就有多少次个function执行,reg找了两次,找第一次时执行一次function($ ,$1)里面的$ ,$1对应的是第一次的,第二次在匹配对应的是第二次的

如果想把选中的字符替换成"$"符号,直接写$是不行的,因为$1、$2代表第一个子表达式第二个子表达式是有语言意义的,如果想强制替换成$就在前面在加上一个$,就相当于在这里面的转义字符。

var reg = /(\w+)\s(\w+)/;

var str = "cainiao gaoshou";

var strNew = str.replace(reg ,'$$ $$');

console.log(strNew);

六、正向预查

要选择一个字符串上面的"a",但这个字符串上面有好几个"a",要选择的这"a"后面要跟着"b"的那个"a"符合要求。选的不是"b","b"就作为一个限制条件,选的还是a。这个就叫“正向预查”或者叫“正向断言”。

var str = "abaaaaa";

var reg = /a(?=b)/g; // a后面跟着(?=b)代表,a后面跟着的是b,但b不参与选择,b只参与修饰、限定

console.log(str.match(reg)); // ["a"]

"非正向预查"/a(?!b)/g,意思后面不是跟着b的那个a,那就多了!

var str = "abaaaaa";

var reg = /a(?!b)/g;

console.log(str.match(reg)); // ["a", "a", "a", "a", "a"]

七、非贪婪匹配

"非贪婪匹配"就是能少就尽量别多

正常的正则表达式的匹配原则是贪婪匹配有多就不少

var str = "aaaaa";

var reg = /a+/g;

console.log(str.match(reg));//["aaaaa"]

可以打破贪婪匹配的原则变成"非贪婪匹配"。

非贪婪匹配就是能少就尽量别多怎么办呢?在任何一个量词的后面在多加一个问号,这样就变成"非贪婪匹配"能少就不多了。

var str = "aaaaa";

var reg = /a+?/g;

console.log(str.match(reg)); // 能一个就不会多个的 ["a", "a", "a", "a", "a"]

这个问号可以打破任何东西,{1,3}正常的返回["aaa", "aa"]

var str = "aaaaa";

var reg = /a{1,3}/g; 

console.log(str.match(reg));//["aaa", "aa"]

打破贪婪匹配加问号,有1就不取3不取2

var str = "aaaaa";

var reg = /a{1,3}?/g; // 加?号有一就不取3

console.log(str.match(reg)); // ["a", "a", "a", "a", "a"]

如果问号后面加问号呢?第一个问号代表量词,第二个问号是取消贪婪匹配。

问号是0到1的意思,那再加一个问号,那只取0不取1,能取0就不取1。

var str = "aaaaa";

var reg = /a??/g;

console.log(str.match(reg)); // ["", "", "", "", "", ""]

 "*号加问号"跟问号加问号差不多,只取0不取1

var str = "aaaaa";

var reg = /a*?/g;

console.log(str.match(reg));// ["", "", "", "", "", ""]

八、

匹配空格

如果要匹配空格怎么办?不用写/S直接写空格就行了。正则表达式里写的任何东西都算是正则表达匹配内容。

var str = "aa aaa";

var reg = / /g;

console.log(str.match(reg));// [" "]

如果想匹配出一个反斜杠怎么办?正则里要写两个

var str = "aa\\aaa"; 

var reg = /\\/g; // 要写两个斜杆

console.log(str.match(reg));//["\"]

如果想正则里想匹配"?"问号,必须加转义因为问号本身就有语法含义,*、+、-也都类似扩号也类似

var str = "aa?a(aa";

var reg = /\?/g;
//var reg = /\(/g; // 括号也类型

console.log(str.match(reg));//["?"]

字符串去重

先找规律\w反向引用一个或者多个

var str = "aaaaabbbbbbbcccccccc";

var reg = /(\w)\1*/g; // 匹配一串重复的

console.log(str.replace(reg, "$1")); // abc

百度面试

2014年百度面试最后一道题,非常有意思,从后位往前面查没隔三位打一个点,要求结果100.000.000

var str = "100000000";

// 怎么把点放进去?换东西,换的是空
// 什么样的空?

// var reg = /($)/g; // 从后往前查,必须$以什么什么结尾
// var reg = /(\d{3}$)/g; // 先解决三个0的问题
// var reg = /((\d{3})+$)/g; // 三位还得是1到多个
var reg = /(?=(\d{3})+$)/g; // 加一个正向预查

console.log(str.replace(reg, ".")); //.100.000.000

完美

var str = "100000000";

var reg = /(?=(\B)(\d{3})+$)/g;

console.log(str.replace(reg, ".")); // 100.000.000



Leave a comment 0 Comments.

Leave a Reply

换一张