目录 |
1.正则的作用
2.正则的元字符及应用
3.正则的创建方式
4.懒惰性和贪婪性
5.分组捕获
6.replace
7.正则的简单应用
1.正则的作用 |
首先什么是正则表达式呢?
正则表达式是是对字符串和特殊字符操作的一种逻辑公式。通俗点说就是一个规则,而且是用来处理字符串的一个规则。
处理可分为两个方面,一个是匹配,另一个是捕获。
- 匹配:判断一个字符串是否符合制定(指定)的规则,即reg.test(str);
- 捕获:把字符串中符合正则规则的内容捕获到,即reg.exec(str);
创建一个正则表达式也有两种方法:
- 字面量方式:var reg = /\d/;
- 实例创建方式:var reg = new RegExp(“str”);
两种创建方式的区别详见第三点:正则的创建方式
2.正则的元字符及应用 |
元字符是指在/ /之间具有意义的一些字符,每一个正则表达式都是有元字符和修饰符组成的。
常见的元字符 |
元字符 | 含义 |
---|---|
\ | 转义字符,转义后面字符所代表的含义 |
^ | 以某一个元字符开始 |
$ | 以某一个元字符结尾 |
* | 出现零到多次 |
+ | 出现一到多次 |
? | 出现零次或一次 |
{n} | 出现n次 |
{n,} | 出现n到多次 |
{n,m} | 出现n到m次 |
\n | 匹配一个换行符 |
. | 除了\n以外的任意字符 |
() | 分组,把一个大正则本身划分成几个小正则 |
[xyz] | x或者y或者z中的一个 |
x|y | x或者y中的一个 |
[^xyz] | 除了三个以外的任何一个字符 |
[a-z] | a-z之间的任何一个字符 |
[^a-z] | 除了a-z之间的任何一个字符 |
\d | 一个0-9之间的数字,相当于[0-9] |
\D | 除了0-9之间的数字以外的任何字符 |
\b | 一个边界符 |
\w | 数字、字母、下划线中的任意一个字符,等价于[0-9a-zA-Z_] |
\s | 匹配一个空白字符(空格、制表符、换页符…) |
[]:在中括号中出现的所有字符都是代表本身意思的字符·,且中括号不识别两位数,例如:/^[12]$/
表示1或2中的一个,/^[12-68]$/
表示1或者2-6或者8中的一个。
元字符的简单应用 |
1.匹配所有数字(正数、负数、小数、0):
/^[+-]?(\d|[1-9]\d+)(\.\d+)?$/
2.验证邮箱(简单版):
/^[\w.-]+@[0-9a-zA-Z]+(\.[a-zA-Z]{2,4}){1,2}$/
3.中国标准真实姓名(2-4个汉字):
/^[\u4e00-\u9fa5]{2,4}$/
4.身份证号码:
/^(\d{2})(\d{4})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|X)$/
5.匹配介于18-65岁之间的所有年龄:
/^1[8-9]|[2-5]\d|6[0-5]$/
3.正则的创建方式 |
一个正则表达式有两种创建方式:
- 字面量方式:var reg = /\d/;
- 实例创建方式:var reg = new RegExp(“str”);
在字面量创建方式中,/ /之间包起来的所有内容都是元字符,有的具有特殊意义,大部分都是代表本身含义的普通元字符。
但是对于字符串拼接的需求,只能使用实例的创建方式,例如:
var name = "abc";
var reg = new RegExp("^\\d+" + name + "\\d+$", "g");
console.log(reg.test("2017abc2017")); //true
两种方式在正则中的区别:
- 字面量方式中出现的一切都是元字符,所以不能进行变量值的拼接,而实例创建方式是可以的
- 字面量方式中直接写
\d
就可以,而在实例中需要把它转义为\\d
附加例子:
var reg = /^(\w)\1(\w)\2$/; //\1代表和第一个分组出现一模一样的内容,\2为第二个
console.log(reg.test("aswq")); //false
console.log(reg.test("aaqq")); //true
4.懒惰性和贪婪性 |
exec:正则的捕获
例如:
var reg = /^1[8-9]|[2-5]\d|6[0-5]$/;
console.log(reg.exec("6565656")); //["56", index: 1, input: "65656565"]
捕获到的内容是一个数组,数组中的第一项是当前大正则捕获的内容;
index:捕获的内容在字符串中开始的索引
input:捕获的原始字符串
正则捕获时,每一次捕获要先进行默认的匹配,如果没有匹配成功,结果是null,只有匹配的内容才能捕获到。
懒惰性 |
懒惰性:每一次执行exec只捕获第一个匹配的内容,在不进行任何处理的情况下,就算执行多次,捕获的还是第一次匹配的内容。
RegExpObject.lastIndex
是正则每一次捕获在字符串中开始查找的位置,默认的值是0,对test的影响可参考:http://www.cnblogs.com/2050/archive/2012/06/26/2563555.html
正则懒惰性的解决方法:在正则的末尾加一个修饰符”g”
修饰符共有3个,分别是”g”、”i”、”m”
- global(g):全局匹配
- ignoreCase(i):忽略大小写匹配
- multiline(m):多行匹配
例如:
var reg = /\d+/;
var str = "abc65468dvf46513se";
console.log(reg.lastIndex); //0
var res = reg.exec(str);
console.log(res); //["65468", index: 3, input: "abc65468dvf46513se"]
console.log(reg.lastIndex); //0
上面代码没有加修饰符g,只能捕获第一个内容
var reg = /\d+/g;
var str = "abc65468dvf46513se";
console.log(reg.lastIndex); //0
console.log(reg.exec(str)); //["65468", index: 3, input: "abc65468dvf46513se"]
console.log(reg.lastIndex); //8
console.log(reg.exec(str)); //["46513", index: 11, input: "abc65468dvf46513se"]
console.log(reg.lastIndex); //16
console.log(reg.exec(str)); //null
加了全局修饰符g,正则每一次捕获结束后,lastIndex的值都变成了最新的值,下一次捕获从最新的位置开始查找,这样可以把需要的内容都捕获到。
捕获正则的所有内容:
var reg = /\d+/g,
str = "abc65468dvf46513se",
ary = [],
res = reg.exec(str);
while (res) {
ary.push(res[0]);
res = reg.exec(str);
}
console.log(ary); //["65468", "46513"]
贪婪性 |
正则的每一次捕获都是按照匹配最长的结果捕获的
解决贪婪性:在量词的元字符后增加?即可,如:var reg = /\d+?/g;
在字符串的方法中,有一个match方法,match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。例如:
var reg = /\d+?/g;
var str = "56sd65dsds48ewqe418";
console.log(str.match(reg)); //["5", "6", "6", "5", "4", "8", "4", "1", "8"]
var reg = /\d+/g;
var str = "56sd65dsds48ewqe418";
console.log(str.match(reg)); // ["56", "65", "48", "418"]
虽然在当前情况下match比exec更加简便一些,但是match中存在一些自己处理不了的问题,即:在分组捕获的情况下,match只能捕获到大正则匹配的内容,而对于小正则的内容是无法获取的。
5.分组捕获 |
正则分组有两个作用:改变优先级和可以进行分组引用
正则在捕获的时候,不仅仅把大正则的内容捕获到,而且把小分组匹配的内容捕获到,例如之前的验证身份证号的正则:
var reg = /^(\d{2})(\d{4})(\d{4})(\d{2})(\d{2})(?:\d{2})(\d)(?:\d|X)$/; //?:的作用是只匹配不捕获
var str = "110226198501272116";
console.log(reg.exec(str)); //["110226198501272116", "11", "0226", "1985", "01", "27", "1", index: 0, input: "110226198501272116"]
该数组的第一项是大正则的匹配内容;第二至九项是每个分组匹配的内容
如果用match()方法,则输出的结果与exec的结果相同:console.log(str.match(reg));
接下来的例子可以看出两者的区别:
var reg = /abc(\d+)/g;
var str = "abc1265abc4896abc5168";
console.log(reg.exec(str)); //["abc1265", "1265", index: 0, input: "abc1265abc4896abc5168"]
console.log(reg.exec(str)); //["abc4896", "4896", index: 7, input: "abc1265abc4896abc5168"]
console.log(reg.exec(str)); //["abc5168", "5168", index: 14, input: "abc1265abc4896abc5168"]
console.log(str.match(reg)); //["abc1265", "abc4896", "abc5168"]
用exec执行三次,每一次不仅把大正则匹配的获取到,而且还可以获得第一个分组匹配的内容。而match只能捕获大正则匹配的内容。
6.replace |
字符串中的replace方法:用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。stringObject.replace(regexp/substr,replacement)
例如:
var str = "abc1234abc4659";
str = str.replace("abc", "abcd");
console.log(str); //"abcd1234abc4659"
str = str.replace("abc", "abcd");
console.log(str); //"abcdd1234abc4659"
在不使用正则的情况下,每执行一次,只能替换一个字符。如果想把所有的abc都替换为abcd,则需要借助正则表达式。
var str = "abc1234abc4659";
str = str.replace(/abc/g, "abcd");
console.log(str); //abcd1234abcd4659
replace原理(默认第一项的值为正则) |
replace方法和exec一样,把所有和正则匹配的都捕获到,然后把捕获的内容替换成需要替换的新元素。
如果把第二个参数换成一个函数:
var str = "abc1234abc4659";
str = str.replace(/abc/g, function () {
console.log(arguments[0]); //获取大正则捕获的内容,即输出两次abc
return "abcd";
});
console.log(str); //把abc替换成abcd,即"abcd1234abcd4659"
那么匿名函数执行多少次,取决于正则能在字符串中捕获多少次。
每一次执行匿名函数,里面传递的参数值arguments和自己通过exec捕获到的结果是非常类似的(即使有分组,也可以通过arguments获取到)。
return返回的结果是什么,相当于把当前这一大正则捕获的内容替换成返回的内容。
arguments的值:如果正则中没有小分组,在全局模式下,匹配几次就输出几次arguments,并且值为匹配的结果;如果正则中有小分组,则arguments为一个或多个类数组,第一项是大正则匹配的内容,第二项开始为小正则匹配的内容。
7.正则的简单应用 |
把数字变成大写 |
var str = "465498715208979";
var ary = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
str = str.replace(/\d/g, function () {
return ary[arguments[0]];
});
console.log(str); //"肆陆伍肆玖捌柒壹伍贰零捌玖柒玖"
获取一个字符串中出现次数最多的字符,并且获取出现的次数 |
function word(str) {
var obj = {}, time = 0, word = [];
for (var key in str) {
obj[str[key]] >= 1 ? obj[str[key]] += 1 : obj[str[key]] = 1;
}
for (var key in obj) {
obj[key] > time ? time = obj[key] : null;
}
for (var key in obj) {
obj[key] === time ? word.push(key) : null;
}
return "出现次数最多的字符是:" + word + " ;出现的次数是:" + time + "次";
}
console.log(word("svniwebviufewrofuwevoifubwe")); //出现次数最多的字符是:w,e ;出现的次数是:4次
其中,第一个遍历数组的循环可以用正则来替换:
str.replace(/[a-z]/gi, function () {
var val = arguments[0];
obj[val] >= 1 ? obj[val] += 1 : obj[val] = 1;
})
模板引擎实现的初步原理 |
var str = "My name is {0},I am {1} years old,I come from {2},I love {3}.";
var ary = ["zzr", "20", "JinLin", "eat"];
str = str.replace(/{(\d+)}/g, function () {
return ary[arguments[1]];
});
console.log(str); //My name is zzr,I am 20 years old,I come from JinLin,I love eat.
获取网络参数 |
转换格式:
URL:"http://sports.qq.com/kbsweb/game.htm?mid=100324:10032369&cid=4444894&app=1.0"
保存成:obj={
mid:"100324:10032369",
cid:"4444894",
app:"1.0"
};
代码如下:
var str = "http://sports.qq.com/kbsweb/game.htm?mid=100324:10032369&cid=4444894&app=1.0";
var reg = /([^?=&]+)=([^?=&]+)/g;
var obj = {};
str.replace(reg, function () {
obj[arguments[1]] = arguments[2];
});
console.log(obj); //{mid: "100324:10032369", cid: "4444894", app: "1.0"}
其中replace方法还可以用如下的exec方法来实现:
var str = "http://sports.qq.com/kbsweb/game.htm?mid=100324:10032369&cid=4444894&app=1.0";
var reg = /([^?=&]+)=([^?=&]+)/g;
var obj = {};
var res = reg.exec(str);
while(res){
obj[res[1]]=res[2];
res = reg.exec(str);
}
console.log(obj); //{mid: "100324:10032369", cid: "4444894", app: "1.0"}
时间格式化 |
把:2017-6-10 19:02:01 变成:2017年6月10日 19时02分01秒
function zero(str) {
str = Number(str);
return str < 10 ? "0" + str : str;
}
function transform(str) {
var templet = "{0}年{1}月{2}日 {3}时{4}分{5}秒";
var reg1 = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})\s(\d{1,2}):(\d{1,2}):(\d{1,2})$/g;
var ary = [];
str.replace(reg1, function () {
ary = [].slice.call(arguments).slice(1, 7);
});
var reg2 = /{(\d+)}/g;
var time = templet.replace(reg2, function () {
return zero(ary[arguments[1]]);
});
return time;
}
console.log(transform("2017-6-10 19:02:01")); //2017年06月10日 19时02分01秒