JS中的正则表达式

本文详细介绍了正则表达式的基本概念、元字符及其应用、创建方式等,包括懒惰性和贪婪性、分组捕获等内容,并提供了实际应用场景示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

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|yx或者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")); //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秒
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值