JS中的正则表达式

来源:互联网 发布:福建随行软件 编辑:程序博客网 时间:2024/05/21 14:53
目录

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

两种方式在正则中的区别:

  1. 字面量方式中出现的一切都是元字符,所以不能进行变量值的拼接,而实例创建方式是可以的
  2. 字面量方式中直接写\d就可以,而在实例中需要把它转义为\\d

附加例子:

var reg = /^(\w)\1(\w)\2$/; //\1代表和第一个分组出现一模一样的内容,\2为第二个console.log(reg.test("aswq")); //falseconsole.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); //0var 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); //0console.log(reg.exec(str)); //["65468", index: 3, input: "abc65468dvf46513se"]console.log(reg.lastIndex); //8console.log(reg.exec(str)); //["46513", index: 11, input: "abc65468dvf46513se"]console.log(reg.lastIndex); //16console.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秒