正则表达式
基本知识
g:全局匹配 i:区分大小写匹配 m:多行匹配
元字符 | 功能 |
---|
. | 匹配除换行符以外任何字符 | \w | 匹配字母或数字或下划线或汉字 | \s | 匹配任意空白符 | \d | 匹配数字 | \b | 匹配单词开始或结束 | ^ | 匹配字符串的开始 | $ | 匹配字符串的结束 | [] | 匹配区间 | \ | 转义 |
重复限定符 | 重复次数 |
---|
* | 0/更多次 | + | 1/更多次 | ? | 0/1次 | {n} | n次 | {n,} | n/更多次 | {n,m} | n到m次 |
实例
分组
/a+/匹配连续出现的“a”,而要匹配连续出现的“ab”时,需要使用/(ab)+/。
其中括号是提供分组功能,使量词“+”作用于“ab”这个整体.
var reg = /(ab)+/g;
var str = "ababa abbb ababab";
console.log( str.match(reg) );
分支
在多选分支结构(p1|p2)中,此处括号的作用也是不言而喻的,提供了子表达式的所有可能。
如果去掉正则中的括号,即/^I love JavaScript|Regular Expression$/,
匹配字符串是"I love JavaScript"和"Regular Expression",当然这不是我们想要的。
var reg = /^I love (JavaScript|Regular Expression)$/;
console.log( reg.test("I love JavaScript") );
console.log( reg.test("I love Regular Expression") );
var reg1= /^I love JavaScript|Regular Expression$/;
console.log( reg1.test("I love JavaScript") );
console.log( reg1.test("He hate Regular Expression") );
引用分组
进行数据提取,以及更强大的替换操作
以日期为例,假设格式是yyyy-mm-dd的,我们可以先写一个简单的正则:
var reg = /\d{4}-\d{2}-\d{2}/;
再改成括号版的:
var reg = /(\d{4})-(\d{2})-(\d{2})/;
var str = "2017-06-12";
提取年、月、日
console.log(str.match(reg)); //["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12", groups: undefined]
match返回的一个数组,第一个元素是整体匹配结果,然后是各个分组(括号里)匹配的内容,然后是匹配下标,最后是输入的文本。(注意:如果正则是否有修饰符g,match返回的数组格式是不一样的,例["2017-06-12", "2018-11-23"])。
正则对象exec方法同
console.log(reg.exec(str)); //["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12", groups: undefined]
也可以使用构造函数的全局属性$1至$9来获取
console.log(RegExp.$1); // "2017"
console.log(RegExp.$2); // "06"
console.log(RegExp.$3); // "12"
替换
yyyy-mm-dd 替换为 mm/dd/yyyy
replace中的,第二个参数里用$1、$2、$3指代相应的分组。
var res = str.replace(reg,"$2/$3/$1");
console.log(res); // "06/12/2017"
等价于
var res = str.replace(reg, function() {
return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;});
等价于
var res = str.replace(reg,function(match,year,month,day) {
return month + "/" + day + "/" + year;});
反向引用
比如要写一个正则支持匹配如下三种格式:
2016-06-12
2016/06/12
2016.06.12
最可能先想到
var reg = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/;
var str = "2017-06-12";
var str1 = "2017/06/12";
var str2 = "2017.06.12";
var str3 = "2016-06/12";
console.log( reg.test(str) ); // true
console.log( reg.test(str1) ); // true
console.log( reg.test(str2) ); // true
console.log( reg.test(str3) ); // true
其中/和.需要转义。虽然匹配了要求的情况,但也匹配"2016-06/12"这样的数据
假设我们想要求分割符前后一致怎么办?此时需要使用反向引用
var reg = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var str = "2017-06-12";
var str1 = "2017/06/12";
var str2 = "2017.06.12";
var str3 = "2016-06/12";
console.log( reg.test(str) ); // true
console.log( reg.test(str1) ); // true
console.log( reg.test(str2) ); // true
console.log( reg.test(str3) ); // false
注意里面的\1,表示的引用之前的那个分组(-|\/|\.)。不管它匹配到什么(比如-),\1都匹配那个同样的具体某个字符
我们知道了\1的含义后,那么\2和\3的概念也就理解了,即分别指代第二个和第三个分组。
看到这里,此时,恐怕你会有三个问题
1.括号嵌套怎么办?
以左括号(开括号)为准。比如:
var reg = /^((\d)(\d(\d)))\1\2\3\4$/;
var str = "1231231233";
console.log( reg.test(str) ); // true
console.log( RegExp.$1 ); // 123
console.log( RegExp.$2 ); // 1
console.log( RegExp.$3 ); // 23
console.log( RegExp.$4 ); // 3
第一个分组是(\d\d\d),忽略了内嵌的括号,所以\1就是123,’1231231233‘的前三个
第二个分组是(\d),忽略外嵌套的括号,所以\2就是1,’123‘的第一个
第三个分组是(\d\d),忽略内外嵌套的括号,所以\3就是23,’123‘的后两个
第四个分组就是(\d),忽略外嵌套的括号,所以\4就是3,’23‘的后面一个
确定\1\2\3\4后就可以接着和’1231233‘判断匹配
即’123 123 1 23 3‘匹配成功
2.\10表示什么呢?
即\10是表示第10个分组,还是\1和0呢?答案是前者,虽然一个正则里出现\10比较罕见。测试如下:
var reg = /(1)(2)(3)(4)(5)(6)(7)(8)(9)(#) \10+/;
var str = "123456789# ######"
console.log( reg.test(str) ); //true
3.引用不存在的分组会怎样?
因为反向引用,是引用前面的分组,但我们在正则里引用了不存在的分组时,此时正则不会报错,只是匹配反向引用的字符本身。例如\2,就匹配"\2"。'\2'对2进行了转义
var reg=/(ab)\1\2/;
console.log(reg.test('abab\2')); //true
var reg = /\1\2\3\4\5\6\7\8\9/;
console.log( reg.test("\1\2\3\4\5\6\7\8\9") ); //true
console.log( "\1\2\3\4\5\6\7\8\9".split("") );
图片不好放,自己f12跑看看
非捕获分组
非捕获性分组工作模式下分组(?:)会作为匹配校验,并出现在匹配结果字符里面,但不作为子匹配返回。
比如利用非捕获性分组获取字符串000aaa111,而且只返回一个值为aaa111的数组:
//先看用捕获性分组匹配会返回什么
var str1 = '000aaa111';
var pattern = /([a-z]+)(\d+)/; //捕获性分组匹配
var arr = pattern.exec(str1);
console.log(arr) //['aaa111','aaa','111'] 结果子串也获取到了,这并不是我们想要的结果
//非捕获性分组 (?:)
var str2 = '000aaa111';
var pattern2 = /(?:[a-z]+)(?:\d+)/; //非捕获性分组匹配
var arr2 = pattern.exec(str2);
console.log(arr2) //['aaa111'] 结果正确
前瞻后顾
前瞻 (?=)和(?!)
前瞻分为正向前瞻和反(负)向前瞻,正向前瞻(?=表达式)表示后面要有什么,反向前瞻(?!表达式)表示后面不能有什么。
前瞻分组会作为匹配校验,但不出现在匹配结果字符里面,而且不作为子匹配返回。如(?=\.jpg),.jpg不出现在返回结果里
正向前瞻匹配一批图片格式,如匹配.jpg后缀文件名
var str = '123.jpg,456.gif,abc.jpg';
var partern = /\w+(?=\.jpg)/g; //正向前瞻匹配
console.log(str.match(partern)); //['123', 'abc'] 返回结果正确,没有匹配456.gif
反向前瞻匹配一批字母加数字,如匹配3个及以上的a,而且后面不能有000的字符
var str = 'aaa000 aaaa111 aaaaaaa222';
var partern = /a{3,}(?!000)/g; //反向前瞻匹配
console.log(str.match(partern)); //['aaaa', 'aaaaaaa'] 返回结果正确,没有匹配aaa000
前瞻,可以放在位置不固定,可前匹配和后匹配,如:/(?=.jpg)\w+/g;
案例1
模拟trim()函数,去掉字符串头尾的空白符
一、匹配开头结尾的空白符替换成空字符
function trim(str){
return str.replace(/^\s+|\s+$/g,'');
}
console.log(trim(' foobar ')); //'foobar' 前后各两空格
二、匹配整个字符串,再提取相应的数据
function trim(str){
return str.replace(/^\s*(.*?)\s*$/g,'$1');
}
console.log(trim(' foobar ')); //'foobar' 惰性匹配,前后空格都删掉了
这里使用了惰性匹配*?,不然也会匹配最后一个空格之前的所有空格的
对比
function trim(str){
return str.replace(/^\s*(.*)\s*$/g,'$1');
}
console.log(trim(' foobar ')); //‘foobar ’ 贪婪匹配,后面的两个空格保留
惰性匹配,贪婪匹配
惰性符号 | 释义 |
---|
*? | 可以重复任意次,但是尽可能重复少的次数 | +? | 可以重复1次或者任意多次,但是尽可能重复少的次数,不过最少次数是1 | ?? | 可以重复0次或1次,但尽可能少重复 | {n,m}? | 可以重复n到m此,但尽可能少重复,最少匹配次数是n | {n,}? | 可以重复n次以上,但尽可能少重复,最少匹配n此 |
贪婪
var s='abbbaabbb123'
var reg=/.*bbb/g;
console.log(reg.exec(s));
惰性
var s='abbbaabbb123'
var reg=/.*?bbb/g;
console.log(reg.exec(s));
函数
test 是regexp 的方法,返回的是布尔值 ,检测对应得字符串是否匹配某种模式 。
var str="catastrop";
var reg= new RegExp("cat","g");
var reg1=/cat/g;
var reg2=/dog/g;
console.log(reg.test(str));
console.log(reg1.test(str));
console.log(reg1.test(str));
exce 是regexp 的方法,查找并返回当前的匹配结果,以数组(长度为1) 的形式返回,不存在返回null
var str="catastrop";
var reg=new RegExp('cat');
var reg1=new RegExp('dog');
var res=reg.exec(str);
var res1=reg1.exec(str);
console.log(res);
console.log(res1);
exec 方法受参数 g 的影响。若指定了 g,则下次调用 exec 时,会从上个匹配的 lastIndex 开始查找。
var str = "1a1b1c";
var reg = new RegExp("1.", "");
console.log(reg.exec(str)[0]);
console.log(reg.exec(str)[0]);
var str = "1a1b1c";
var reg = new RegExp("1.", "g");
console.log(reg.exec(str)[0]);
console.log(reg.exec(str)[0]);
match是 String 对象 的一个方法,查找并返回当前的匹配结果,并以数组(长度为1) 的形式返回,不存在返回null
var str="catdogcat";
var reg=new RegExp("cat");
var reg1=new RegExp('lion');
console.log(str.match(reg));
console.log(str.match(reg1));
match的非全局模式跟exec的方法返回值是一样的,如果指定了参数g ,那么match一次返回所有结果
var string="catdogcatdog";
var reg=new RegExp("cat","g");
console.log(string.match(reg));
string
|