REGEXP对象
javascript通过内置对象RegExp支持正则表达式
有两种方法实例化RegExp对象
1、字面量
var reg = /\bis\b/;
var reg2 = /\bis\b/g; //正则规则放在//内,\bv表示单词边界,g表示全文搜索,如果没有g则只会修改符合条件的第一个值
var str = 'He is a boy. this is a dog. where is she?'
str.replace(reg, 'IS');//"He IS a boy. this is a dog. where is she?"
str.replace(reg2, 'IS');//"He IS a boy. this IS a dog. where IS she?"
2、构造函数
new RegExp(pattern,attributes)接收两个参数
参数 pattern 是一个字符串,指定了正则表达式的模式或其他正则表达式。
参数 attributes 是一个可选的字符串,包含属性 “g”、“i” 和 “m”
var reg = new RegExp('\\bis\\b');//两个\\第一个表示转义符
var reg = new RegExp('\\bis\\b');
var reg2 = new RegExp('\\bis\\b', 'g');
'He is a boy. this is a dog. where is she?'.replace(reg, 'IS');//"He IS a boy. this is a dog. where is she?"
'He is a boy. this is a dog. where is she?'.replace(reg2, 'IS');//"He IS a boy. this IS a dog. where IS she?"
正则修饰符介绍
g: global全文搜索,不添加,搜到第一个匹配即停止,后面符合条件的不会被替换
i:ignore case 忽略大小写,默认是大小写敏感的
m:multiple lines多行搜索
"He IS a boy. this IS a dog. where is she?".replace(/\bis\b/gi, 'a');//全文搜索且不区分大小写"He a a boy. this a a dog. where a she?"
**
元字符与元义文本字符
**
元义文本字符:原本的字符的意思,比如abc就是指abc
元字符:有特殊含义的非字母字符,比如* + ? $ ^ . | \ () {} []
字符 |
含义 |
\t |
水平制表符 |
\v |
垂直制表符 |
\n |
换行符 |
\r |
回车符 |
\0 |
空字符 |
\f |
换页符 |
\cX |
与X对应的控制字符(ctrl + X) |
备注:元字符的含义不是唯一的,在不同的情况有不同的含义,例如^在中括号[]内为取反的意思,在别的地方还有以xxx开始的意思
字符类
'ab\tabc-abd'.replace(/ab\t/, '11'); //一一对应"11abc-abd"
//用[]泛指一个简单的类,有[]中的任何一个都会替换
'a1b2c3d4'.replace(/[abc]/g, 'x'); //包含abc的任何一个都被替换为x,而非将abc替换为x "x1b2c3d4"
//取反
'a1b2c3d4'.replace(/[^abc]/g, 'x');//"axbxcxxx" 不是a或者b或者c的都被替换
范围类
[a-z] 从a到z的任意字符,是一个闭区间,包含a和z本身
'a1b2c3d4'.replace(/[a-z]/g, 'Q');// "Q1Q2Q3Q4"
'a1b2c3d4'.replace(/[a-c]/g, 'Q');//"Q1Q2Q3d4"
'aA1bBCD2c3d4'.replace(/[a-cA-B]/g, 'Q');//小写大写可以连接,如果是这种写法属于范围,不能替换- "QQ1QQCD2Q3d4"
'2021-03-31'.replace(/[0-9]/g, 'P');//"PPPP-PP-PP"
'2021-03-31'.replace(/[0-9-]/g, 'P');//"PPPPPPPPPP"
**
预定义类
**
预定义类匹配常见的字符
字符 |
含义 |
^ |
以xxx开始 |
$ |
以xxx结束 |
\b |
单词边界 |
\B |
非单词边界 |
'this is a boy'.replace(/is/g, '0');//"th0 0 a boy"不界定单词边界,有is的都被替换包括单词中的字母
'this is a boy'.replace(/\bis\b/g, '0');//"this 0 a boy" 界定单词边界
'this is a boy'.replace(/\Bis\b/g, '0');//"th0 is a boy" 左边为非单词边界,右边为单词边界只有this满足
'@abc@ef@'.replace(/@./g, 'Y');//"YbcYf@" 替换@+任意字符的
'@abc@ef@'.replace(/.@/g, 'Y');//"@abYeY" 替换任意字符+@
'@abc@ef@'.replace(/^@./g, 'Y');//"Ybc@ef@" 替换开头为@
'@abc@ef@'.replace(/.@$/g, 'Y');//"@abc@eY" 替换结尾为@
量词
匹配一个 连续出现 20次 数字的字符串,如果没有量词,则需要连续写20次匹配
字符 |
含义 |
? |
出现零次或一次(最多出现1次) |
+ |
出现一次或多次(至少出现一次) |
* |
出现零次或多次(任意次) |
{n} |
出现n次 |
{n,m} |
出现n到m次,包括n和m |
{n,} |
至少出现n次 |
var res = /\d{3,6}/;
'12abcdssd'.match(res);//null,数字没有出现3到6次
'12abcds54455sd'.match(res);//["54455"],将至少出现3-6次的数字返回,结果为数组的形式
'1255abcds54455sd'.match(res);// ["1255", "54455"]
'12abcds54455sd'.replace(/\d{3,6}/g,'Q');//"12abcdsQsd"
'123abcds54455sd'.replace(/\d{3,6}/g,'Q');//"QabcdsQsd"
贪婪模式和非贪婪模式
//贪婪模式
'12345678'.replace(/\d{3,6}/g, 'X');//"X78" 按照尽可能多的6匹配,而非3匹配成XX78
非贪婪模式:让正则表达式尽可能少的匹配,也就是说一旦成功匹配不再继续尝试
//非贪婪模式
'12345678'.replace(/\d{3,6}?/g, 'X');//"XX78" 数字字符出现3-6次
'12345678'.match(/\d{3,6}?/g);//["123", "456"]
分组
例如:匹配字符串Byron连续出现3次的场景,如果使用量词
//匹配的为Byron单词中n连续出现3次,而非这个单子连续出现3次
'ByronByronByron'.match(/Byron{3}/);//null
'ByronnnaaaaByronnnbbbb'.match(/Byron{3}/g);(2) ["Byronnn", "Byronnn"]
//分组用小括号()括起来
'ByronByronByron'.match(/(Byron){3}/g);//["ByronByronByron"]
//分组中|或的使用
'tellTitle'.replace(/tell|Title/g, 'Q');//tell或者Title "QQ"
'tellitleAAtelTitle'.replace(/tel(l|T)itle/g, 'Q');//tellitle或telTitle,单词中间一个字母不同,而非两个单子不同 "QAAQ"
//反向引用,分组后可以用$来捕获,第一个分组为$1
//将2015-12-25替换为12/25/2015
'2015-02-15'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$1');//"2015"
'2015-02-15'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2');//"02"
'2015-02-15'.replace(/(\d{4})-(\d{2})-(\d{2})/g,$3);//"undefined"
'2015-02-15'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$3');//"15"
'2015-02-15'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2/$3/$1');//"02/15/2015"
//忽略分组,分组内前面加上问号冒号?:
'2015-02-15'.replace(/(?:\d{4})-(\d{2})-(\d{2})/g,'$1');//"02" 此时第一个分组被忽略,第二个分组编号为$1
前瞻后顾
1、正则表达式从文本头部向尾部开始解析,文本尾部方向,称为“前”(通俗的说,像走路,尾部为未走过的路,所以是前面,头部解析过的为走过的路,为后)
2、前瞻:在正则表达式匹配到规则的时候,向前检查是否符合断言
3、后顾/后占:方向相反
4、javascript不支持后顾
5、符合特定断言称为 肯定/正向 匹配;不符合特定断言称之为 否定/负向 匹配
名称 |
正则 |
正向前瞻 |
exp(?=assert) |
负向前瞻 |
exp(?!assert) |
正向后顾 |
exp(?<=assert) javascript不支持 |
负向后顾 |
exp(?<!assert) javascript不支持 |
exp表示正则条件,括号内为断言部分
//单词字符且单词字符(\w 字母数字下划线)后面为数字,数字为断言部分,不会被替换
'aa22_ab_24'.replace(/\w(?=\d)/g, 'Q');//"aQQ2_abQQ4"
//第一个a虽然是字母,但后面跟的a而非数字不满足断言,所以第一个a不被替换,第二个a满足被替换,第一个2满足数字后面跟数字,所以第一个2也被替换,第一个_后面不是数字不满足断言
'aa22_ab_24'.replace(/\w(?!\d)/g, 'Q');//"Qa2QQQQ_2Q" 断言为不是数字
与正则表达式相关的方法
对象属性:
1、global:是否全文搜索,默认false
2、ignore case:是否大小写敏感,默认false
3、multiline:多行搜索,默认false
4、lastIndex:当前表达式匹配内容的最后一个字符的下一个位置
5、source:正则表达式的文本字符串
//这几个属性是只读的,不能进行设置
var reg1 = /\w/;
var reg2= /\w/gim;
reg1.global;//false
reg1.global;//false
reg1.ignoreCase;//false
reg.multiline;//false
reg2.global;//true
reg2.ignoreCase;//true
reg2.multiline;//true
//不能对这几个属性进行设置,例如
reg1.global = true;
reg1.global;//依然为false
test()方法,RegExp.prototype.test(str)
用于测试字符串参数中是否存在匹配正则表达式模式的字符串,常用语input输入验证
var reg1 = /\w/;
var reg2= /\w/gim;
reg1.test('a');//true
reg1.test('$');//false
//无论执行几次,结果都一样
//但是reg2的结果则有所不同,这是因为lastIndex属性的原因
reg2.test('ab');//true
reg2.test('ab');//true
reg2.test('ab');//false
reg2.test('ab');//true
while(reg2.test('ab')){
console.log(reg2.lastIndex);// 1 2
}
//因为是全局检测,下次检测记住了上次检测位置,不是每次都从头检测,第一次检测a满足正则表达式,a后面为b所以lastIndex为1,第二次检测b,b后面没有了所以返回false,然后重置为0,所以第四次又变为true
//解决方法,因为test是检测有没有,不管第几次,所以可以不用g标志即可解决
reg1.test('ab');//true
exec()方法,RegExp.prototype.exec(str)
使用正则表达式模式对字符串执行搜索,并将更新全局RegExp对象的属性以反映匹配结果
如果没有匹配的文本返回null,否则返回一个结果数组,数组中有两个属性:
——index 声明匹配文本的第一个字符的位置
——input 存放被检索的字符串 string
非全局调用
调用非全局的RegExp对象的exec()时,返回的数组
1、第一个元素为与正则表达式相匹配的文本
2、第二个是与RegExpObject的第一个子表达式相匹配的文本(如分组,有的话展示,无不展示)
3、第三个是与RegExpObject的第二个子表达式相匹配的文本(如分组,有的话展示,无不展示)
var reg1 = /\d(\w)\d/;
var str= '@1a2bb3c5678';
var ret= reg1.exec(str);
console.log(ret);
//["1a2", "a", index: 1, input: "@1a2bb3c5678", groups: undefined]
// 1a2表示与正则表达式相匹配的文本
// a表示分组的内容
// index:1 表示匹配的第一个字符,从0开始,1为第二个,所以下标为1
// input: '@1a2bb3c5678' 被检索的字符串
var reg2 = /\d(\w)(\w)\d/;//两个分组
var str2= '@1at2bb3c5678';
var ret= reg2.exec(str);
// ["1at2", "a", "t", index: 1, input: "@1at2bb3c5678", groups: undefined]
//a t为匹配的分组文本内容
console.log(reg1.lastIndex);//0 非全局g的状态lastIndex是不生效的,没有作用的
全局调用
var reg3 = /\d(\w)\d/g;
var str3= '@1a2bb3c56&8';
// var ret= reg3.exec(str3);
// console.log(reg3.lastIndex, ret);
// var ret= reg3.exec(str3);
// console.log(reg3.lastIndex, ret);
// var ret= reg3.exec(str3);
// console.log(reg3.lastIndex, ret);
// var ret= reg3.exec(str3);
// console.log(reg3.lastIndex, ret);
while( ret= reg3.exec(str3) ){
console.log(reg3.lastIndex + '\t' + ret.index + '\t' + ret);
//4 1 1a2,a 1a2后面的b下标为4,1a2的1下标为1,1a2为满足正则条件的文本,a为分组的文本
//9 6 3c5,c 3c5后面的6下标为9,3c5的3下标为6,3c5为满足正则条件的文本,c为分组的文本
}
字符串方法
下面的字符串方法也可以用于正则表达式
原理:会将传入的字符串尝试转为正则
'a1b2c3'.search('1');// 1 查找字符串1也可以找到
'a1b2c3'.search(1); // 1 查找数字1也可以找到
1、search方法,String.protatype.search(str/reg)
用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串
返回第一个匹配结果 index(下标),查不到返回-1
search方法不执行全局匹配,它将忽略 g 标志,并且总是从字符串的开始进行检索
var str= 'abdckjj';
str.search('kjj');//4
str.search('qq');//-1
str.search(/j/);//5 只查找第一个j出现的位置
str.search(/\w/);//0 第一个既满足,所以下标为0
str.search(/j/g);//5 会忽略g,依然只返回第一个j出现的位置
2、match方法,String.protatype.match(str/reg)
match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置
没有找到则返回null
非全局调用
var str= 'abdckjj';
str.match('jj'); //["jj", index: 5, input: "abdckjj", groups: undefined]
str.match('bd');//["bd", index: 1, input: "abdckjj", groups: undefined]
备注:非全局调用返回结果类似exec方法,区别exec为正则表达式.exec(字符串参数),match为字符串.match(正则表达式参数)
全局调用
var reg4= /\d(\w)\d/g;
var ts = '$1a2b3c4d5e';
ret = ts.match(reg4);
console.log(ret);//["1a2", "3c4"],只返回匹配结果,没有位置也没有分组内容
console.log(ret.index + '\t' + reg4.lastIndex);//undefined 0
3、split方法,String.protatype.split(str/reg)
split() 方法用于把一个字符串分割成字符串数组
也可以传入正则
'abcdef'.split();//["abcdef"]
'abcdef'.split('');//["a", "b", "c", "d", "e", "f"]
'a,b,c,d,e,f'.split(',');//["a", "b", "c", "d", "e", "f"]
//相当于隐士转换为正则 'a,b,c,d,e,f'.split(/,/);
'a1b2c3d4'.split(/\d/);//["a", "b", "c", "d", ""]
4、replace方法,String.protatype.replace(str/reg)
replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串
'a1b'.replace('1',2);//"a2b"
'a1b1c1d'.replace('1',2);//"a2b1c1d" 只替换了第一个
'a1b1c1d'.replace(/1/g,2);//"a2b2c2d" 替换了所有
String.protatype.replace(reg, function)
function参数含义
function会在每次匹配替换的时候调用,有4个参数,具体参数个数看是否有分组,有几个分组
1、匹配字符串
2、正则表达式分组内容,没有分组则没有该参数
3、匹配项在字符串中的index
4、原字符串
//将字符串中的所有数字都在原有基础上+1
var str1='a1b2c3d4e5';
var x=str1.replace(/\d/g, function (param, index, origin) {
console.log(param,index, origin);
//param 匹配的字符串
//index 匹配字符串的下标
//origin 原字符串
// console.log(typeof (param-0));
// return param-0+1; //利用减法运算也可以将字符串转为number类型
return parseInt(param) +1;
})
console.log(x); //a2b3c4d5e6
console.log(str1);//a1b2c3d4e5 不会修改原字符串
var x2 = str1.replace('a1', 'Q');
console.log(x2);//Qb2c3d4e5
//将a1b2c3d4e5中的bc去掉
var str2 = 'a1b2c3d4e5';
var y = str2.replace(/(\d)(\w)(\d)/g, function(match, group1, group2, group3, index, origin){
console.log(match, group1, group2, group3);
return group1 + group3
})
console.log(y); //a12c34e5