正则表达式

正则表达式

正则表达式(regular expression)是一个描述字符模式的对象。
ECMAScript的RegExp类表示正则表达式。
而string和RegExp都定义了使用正则表达式进行强大的模式匹配和文本检索与替换的函数。

简单的模式可以是一个单独的字符。a
更复杂的模式包括了更多的字符,并可用于解析、格式检查、替换等等。
您可以规定字符串中的检索位置,以及要检索的字符类型,等等。

正则表达式只是一个字符串。没有长度限制,但是,这样的正则表达式长度往往较短。如下所示是一些正则表达式的例子:

I had a \S+ day today
[A-Za-z0-9\-_]{3,16}
\d\d\d\d-\d\d-\d\d
v(\d+)(\.\d+)*
TotalMessages="(.*?)"
]>

这些字符串实际上都是微型计算机程序。
正则表达式的语法,实际上是一种轻量级、简洁、适用于特定领域的编程语言。

创建正则表达式

  • 使用字面量创建:​​var re = /a/​
  • 使用RegExp构造函数创建:​​var re = new RegExp(“a”,“修饰符”);​
  • g 全局 从头查找到尾部
  • i 不区分大小写
  • m 支持换行操作
var reg=new RegExp("a","g");
console.log(reg.flags);//修饰符
console.log(reg.source);//正则内容

正则表达式对象的方法

方法

功能

test()

返回一个布尔值,方法用于匹配字符串,匹配成功返回true,失败返回false

exec()

方法检索字符串中的指定值。返回值是被找到的值。如果没有发现匹配,则返回 null。

var reg=/a/g;

console.log(reg.test("abac"));
console.log(reg.test("abac"));
console.log(reg.test("abac"));//false
console.log(reg.test("abac"));//重新从第一个开始查找

注意:

在一个正则对象使用test或者exec时,如果使用全局查找,将自动记录查找指针,同一个正则对象再次查找指针会继续上次的位置开始向后查找
exec 使用全局g无效 一次无法全部找到,多次可以使用全局g

常用字符串匹配的正则方法

方法

功能

replace()

用于替换,接受两个参数,第一个是匹配项,第二个可以是字符串或是一个函数

match()

接受一个参数,正则去匹配字符串,如果匹配成功,就返回匹配成功的数组,如果匹配不成功,就返回null

search()

参数与match相同,返回字符串中第一个匹配项的索引,没有匹配项返回-1

Split()

把字符串分割为字符串数组。

找见某一个字符并换掉

var str="abcdefB";
str=str.replace(/c/,"z");
console.log(str);//abzdefB

全局 从头查找到尾部

str=str.replace(/b|e/g,"z");//(或)全局  从头查找到尾部
console.log(str);
str=str.replace(/b|e/gi,"z");//i 不区分大小写

替换

var str='{"a":1,"b":2,"c":3}';
str=str.replace(/"/g,"'");
console.log(str)
//{'a':1,'b':2,'c':3}

search在使用g时无效

console.log("abacad".search(/a|d/g))
//0

match 查找内容

console.log("abacad".match(/a|d/g));
['a', 'a', 'a', 'd']

可以使用正则表达式多种符号切割字符

console.log("a-b-c".split("-"));//['a', 'b', 'c']
console.log("a=b-c".split(/=|-/));//['a', 'b', 'c']

替换

var str="abacad".replace(/c|d/g,"z");
console.log(str);//abazaz

replace不但可以查找一个,通过正则表达式可以查找多个,也可以替换为不同的内容

var i=0;
var str="abacad".replace(/c|d/g,function(item,index,str){
console.log(item,index,str);
i++;
return i;
})
console.log(str)//aba1a2
var str = "abc345hh67";
var reg = /\d{2}/;

console.log(str.match(reg));//['34', index: 3, input: 'abc345hh67', groups: undefined]
console.log(str.search(reg));//3
console.log(str.replace(reg,"哈哈哈哈"));//abc哈哈哈哈5hh67

元字符

修饰符

修饰符

功能

i

执行对大小写不敏感的匹配。

g

执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。

m

执行多行匹配。

字符匹配

正则表达式中包含了一系列的字符,这些字符只能匹配它们本身。有一些被称为“元字符”的特殊字符,可以匹配一些特殊规则。
如下所示的例子中,我用蓝色标出了元字符。
I had a \S+ day today
[A-Za-z0-9\-_]{3,16}
\d\d\d\d-\d\d-\d\d
v(\d+)(\.\d+)*
TotalMessages="(.*?)"
]*>

点通配符

  • 这是我们第一个讲解的元字符,“.”相当于CSS中*,它意味着可以匹配所有的字符,称之为通配符。
  • ​/c.t/​​​ 就是第一个字符是​​c​​​,第二个字符是任意字符,第三个字符是​​t​​​。注意如果​​ct​​​,或者​​coot​​是不符合规则的。
  • ​/c\.t/​​​ 如果用​​\.​​​ 来描述,.在这里就不是通配符了,而是表示第一个字符是​​c​​​,第二个字符是.,第三个字符是​​t​
  • 这里的反斜杠其实也是元字符,表示把一些元字符恢复到原来的字符功能。

注意:在元字符中.不能用于 匹配换行符,因为换行符在不同的表示方法中实现不同。

方括号范围匹配

只有满足[ ]任意一个字符
字符类是一组在方括号中的字符【a-z】【A-Z】【0-9】
例如

  • ​c[aeiou]t​​ 第一个字符是c,第二个字符可以是a,e,i,o,u中的任意一个字符,第三个字符是t。
  • [012345679] 匹配数字中除了8以外的任意一个整数
  • ​[a]​​匹配单一字符a
  • ​[\[\]\ab]​​ 仅匹配一个字符,[ 意味着匹配“[”,]意味着匹配“]”,\ab,意味着匹配一个a或者b的字符。
  • ​[\\\[\]]​​ ???这是什么
console.log('\\[]'.match(/\\\[\]/));// 输出:['\\[]', index: 0, input: '\\[]', groups: undefined]
console.log('\\[]');// 输出:\[]
  • ​[dabaaabcc]​​ 注意这里出现了重复和顺序问题,这种写法其实没有任何意义,与[abcd]相同
  • ​[.]​​​ 这种元字符是匹配.,与.单独出现是不同的。他表示必须匹配一个字符全角字符句号,与单独出现与.的作用也不相同,后者是一个.字符。​​/[.]/​​ 代表字符. 不是通配符
  • 字符类描述的过程中可以省略中间值,用-直接连接首尾,例如[a-z]a-z的所有字符,[f-z]f-z的所有字符
  • ​[1-9]​​1,2,3,4,5,6,7,8,9
  • ​[A-Z]​​大写的A到Z的所有字符匹配
  • ​[0-9.,]​​匹配0到9的任意数字或者全角句号或者逗号
  • ​[0-9A-F]​​匹配0到9的任意数字或者大写A到大写F的任意字符
  • ​[0-9a-z\-]​​ 匹配0-9,a-z的任意数组或者字符,或者-字符
  • 一般我们用​​[]​​​这种字符类匹配是为了在匹配是某些字符可以是多个字符。所以单独使用​​[a]​​​与​​a​​是一样的作用。

错误提示
即使[A-z]在你使用的实现中,是合法的,也可能会产生无法预料的运行结果。

[1-31] 这是什么??1,2,3还是1-31
[1-31] 匹配的是123中的某一项
console.log(/[{}]/);//匹配{ 和 }任意一个字符

方括号字符反义

[^]反义字符,表示除了^所描述的字符外的其他字符,类似于js中!的作用。
[^a]
[^a-zA-Z0-9]
[\^abc]
[^\^]

转义字符类

项目

Value

​\w​

查找单词字符。与[a-zA-Z_0-9]相同

​\W​

查找非单词字符。[^0-9A-Za-z_]相同

​\d​

查找数字。与[0-9]相同

​\D​

查找非数字字符。与[^0-9]相同

​\s​

查找空白字符。

​\S​

查找非空白字符。

\b

单词分割符

\B

非单词分割符

用空格切割

console.log("ab cd ef".split(/\s/));//用空格切割
// ['ab', 'cd', 'ef']

用非空格匹配后的字符数组转为字符串

console.log(" aja ajsn  asd  assd a a sa asd ".match(/\S/g).join(""));

重复匹配

​m{n}​​ 表示m重复n次

console.log(/1[3-9]\d\d\d\d\d\d\d\d\d/.test("13890876890"))
console.log(/1[3-9]\d{9}/.test("13890876890"))

普通重复

console.log(/ab{3}/)  //abbb
console.log(/(ab){3}/) //ababab
console.log(/a{1}/)// 等价与/a/
console.log(/a{0}/)// 匹配""字符
console.log(/\d\d\d\d-\d\d-\d\d/)
console.log(/\d{4}(-\d{2}){2}/)

重复次数范围+贪婪匹配

​{最低,最多}​

console.log("caab".match(/ca{3,8}b/))//null
console.log("caaab".match(/ca{3,8}b/))
console.log("caaaaaaaab".match(/ca{3,8}b/))
console.log("caaaaaaaaab".match(/ca{3,8}b/))//null
console.log("a1231241231b".match(/a\d{1,20}b/));
console.log("a1b".match(/a\d{0,20}b/));//可以是:"ab","a1b";
//任意字符一位或者40位之间
console.log("a1283712387basvad18927318273v".match(/a.{1,40}v/g));//['a1283712387basvad18927318273v']
console.log("aaaaaaaa".match(/a{3,5}/g));// ['aaaaa', 'aaa']

不给最大值,表示无穷大(0个也好,无数也罢)

console.log("aaaaaaaaa".match(/a{0,}/g));//不给最大值,表示无穷大

几种不同的取值情况

console.log("a".match(/a{0,}/g));
//['a', '']
console.log("a".match(/a{0}/g));
//['', '']
console.log("a".match(/a{1}/g));
//['a']
console.log("colour".match(/colou{0,1}r/g));
//可有可无

所以就有了几种简写模式

{0,} _ ​​*​

0个也好,无数也罢

{1,} _ +

整一个及以上

{0,1} _

可有可无

非贪婪匹配

在​​.​​​字符后面有​​*?​​​或者​​+?​​通通称之为非贪婪匹配;

console.log("av1283712387basvad18927318273v".match(/a.+?v/g));
// ['av1283712387basv', 'ad18927318273v']
console.log("av1283712387basvad18927318273v".match(/a.*?v/g));
// ['av', 'asv', 'ad18927318273v']
console.log("中国的四大名著包括《西游记》、《三国演义》、《水浒传》、《红楼梦》".match(/《.+?》/g))
//['《西游记》', '《三国演义》', '《水浒传》', '《红楼梦》']
var str = "<p>Uber的这款无人车原型配备了多个<strong>摄像头</strong>、<em>激光雷达</em>以及<span>传感器</span>,可看清100米范围内任何方向的东西</p><br/><p>第二行内容,哎嘿,第二行内容</p>";

str=str.replace(/<.+?>/g,function(item){
return item==="<br/>"? "\n" : "";
})

起始和结束符

项目

Value

​^​​ 起始

正则表达式开始的位置加入这个表示整个字符串必须以这个字符起始

​/^a/​

必须以a作为开始

​$​​结束

正则表达式结束的位置加入这个表示整个字符串必须以这个字符结束

​/a$/​

必须以a结束

  • 如果使用^和$ 可以约束整个字符串的长度限制
  • 必须把^ 写在第一位处理
console.log(/^ab$/.test("ab"))//true
console.log(/b.{4}$/.test("asdhjasdbaaaa"));//匹配后几位是b的结尾

​|​​ 或者

注意:如果这里的写两个||表示对空字符也会做一个匹配
如果匹配成功,不会进行后面正则判断

console.log(/cat|dog/.test("dog"));
console.log(/cat|dog/.test("cat"));

console.log("abacad".match(/ab||ac/g));
console.log("abacad".match(/ab|ac|/g));
console.log("abacad".match(/|ab|ac/g));

true
true
['ab', '', '', '', '', '']
['ab', 'ac', '', '', '']
['', '', '', '', '', '', '']
/a|b/ 等价于 [a|b]

案例锦集:

匹配1-31

/^[1-9]$|^[12]\d$|^3[01]$/

匹配0-255

/^\d$|^[1-9]\d$|^1\d{2}$|^2[0-4]\d$|^25[0-5]$/

匹配IP地址

0.0.0.0-255.255.255.255
/^(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])){3}$/

群组

  1. ( )可以将部分正则内容作为一组使用
  2. 可以筛选出字符串中符合需求的部分
  3. 将括号里的东西放在这个获取数组的后面部分

例如:

var str="3<ab>";
console.log(str.match(/(\d+)<([a-zA-Z]+)>/))

网址正则

var str="http://www.163.com/news/a/b/index.html";
console.log(str.match(/(https?:)\/\/([^\/]+)(.+\/)(.*)/));

match不允许群组的全局查找

群组の替换

var str="3[ab]12[cd]";
str=str.replace(/(\d+)\[([a-zA-Z]+)\]/g,function(item,a,b){
// console.log(item,a,b);
return b.repeat(a);
});
console.log(str)
//abababcdcd

群组替换,对象赋值

var str="a=3&b=a&c=5&d=6";
var o={};
str.replace(/(\w+)=([^&]+)/g,function(item,a,b){
o[a]=isNaN(b) ? b : Number(b);
})
console.log(o)

群组替换

var str="18617890567";
// 群组1 $1
// 群组2 $2
str=str.replace(/(\d{3})\d{4}(\d{4})/,"$1****$2");
console.log(str);
186****0567
var str="11012219980524401X";
str=str.replace(/(\d{4})\d{11}(\d{3}|\d{2}X)/,"$1***********$2");
console.log(str);
1101***********01X
面试题
var str="3[2[a]3[bc]]2[ab]";

function stringify(str){
if(!/\d+\[\w+\]/.test(str)) return str;
return stringify(str.replace(/(\d+)\[(\w+)\]/g,function(item,a,b){
return b.repeat(a);
}));
}
str= stringify(str);
console.log(str)

断言

后置肯定断言​​?=n​

判断a的后面是不是d,如果是则替换这个a
var str="abadae";
console.log(str.replace(/a(?=d)/g,"0"));
//ab0dae

后置否定断言 ​​?!n​

判断a的后面是除了d的a之外的所有a被替换
var str="abadae";
console.log(str.replace(/a(?!d)/g,"0"));
//0bad0e

前置肯定断言 ​​?<=n​

看箭头指向,b的前面是c的这样的b,被替换
var str="abcbdb";
console.log(str.replace(/(?<=c)b/g,"0"))
//abc0db

前置否定断言 ​​?<!n​

判断b前面是除了c的a之外的所有b被替换0
var str="abcbdb";
console.log(str.replace(/(?<!c)b/g,"0"))

​"3+5="-->"3+5=8"​​面试题

var str="1+2+3=";
str=str.replace(/(?<=\=)/,function(item,index,str){
return str.match(/(\d+)\+(\d+)\+(\d+)/).slice(1).reduce(function(v,t){
return Number(v)+Number(t);
})
})
console.log(str);

高级密码

(?=\D+\d) 起始字符开始首字母不能是数字,但是在整个字符串中必须包含数字
(?=.*[a-z]) 在任意位置包含a-z的小写字母
(?=.*[A-Z]) 在任意位置包含A-Z的大写字母
[a-zA-Z0-9_-$&!]{8,16} 密码实际包含的字符,要求最少8位,最大16位
/^(?=\D+\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9_\-$&!]{8,16}$/

中级密码

console.log(/^(?=\D+\d)(?=.*[a-z])[a-zA-Z0-9_\-$&!]{8,16}$|^(?=\D+\d)(?=.*[A-Z])[a-zA-Z0-9_\-$&!]{8,16}$|^(?=.*[A-Z])(?=.*[a-z])[a-zA-Z0-9_\-$&!]{8,16}$/.test("xietian12"))

初级密码

console.log(/^\d{8,16}$|^[a-z]{8,16}$|^[A-Z]{8,16}$/.test("xietianabc"))

重复次数

(n)\1* 不重复也可以查找到
(n)\1+ 至少重复1次以上的可以查找到
n就是正则内容

输出字符的个数面试题

var str="hjhjds jksjsdkj alkjd jksdj kswdjli qwdo qijd aksijdais  asdiuaiusd asdiuasdkjh";

var o=str.split("").sort().join("").match(/(.)\1*/g).reduce(function(v,t){
// console.log(t,t[0],t.length);
v[t[0]]=t.length;
return v;
},{});
console.log(o)

变量

5、变量 (?<变量>筛选的字符)
把筛选出来的给变量

var str="3[ab]";
var reg=/(?<n>\d+)\[(?<m>\w+)\]/g;
console.log(str.match(/(?<num>\d+)\[(?<str>\w+)\]/).groups)
//{num: '3', str: 'ab'}
str.replace(/(?<num>\d+)\[(?<str>\w+)\]/,function(item,a,b,index,str,groups){
console.log(groups)
})
//{num: '3', str: 'ab'}

增添addClass

<div class="div1 div2   div3"></div>
========================================
function addClass(elem,className){
elem.className=className.match(/\S+/g).reduce(function(v,t){
if(!v.includes(t)) v.push(t);
return v;
},elem.className.match(/\S+/g)).join(" ")
}

var div=document.querySelector("div");
addClass(div," div2 div4 div5 ")

删除removeClass

function addClass(elem,className){
elem.className=className.match(/\S+/g).reduce(function(v,t){
if(!v.includes(t)) v.push(t);
return v;
if(v.includes(t)) v.splice(t);//暂存
},elem.className.match(/\S+/g)).join(" ")
}

var div=document.querySelector("div");
addClass(div," div2 div4 div5 ")

中文查询

中文匹配
/[\u4e00-\u9fd5]{2,4}/