文章已同步至掘金:https://juejin.cn/post/6844903954254413837
欢迎访问😃,有任何问题都可留言评论哦~
正则表达式很不容易看懂,就算你看完了所有的字符代表的含义,你可能还是一脸懵逼
所以我认为需要把字符所代表的含义和例子结合起来,一起看,这样就会很容易看懂的
语法结构 {#%E8%AF%AD%E6%B3%95%E7%BB%93%E6%9E%84}
/正则表达式主体/修饰符(可选)
修饰符:
- i (搜索不区分大小写)
- g (全局匹配)
- m (执行多行匹配)
- u (匹配宽字节)
使用字面量创建 {#%E4%BD%BF%E7%94%A8%E5%AD%97%E9%9D%A2%E9%87%8F%E5%88%9B%E5%BB%BA}
let str = 'fanjunyang'
let dete = 'j'
`console.log(eval(``/${dete}/``).test(str)); // true
`
元字符 {#%E5%85%83%E5%AD%97%E7%AC%A6}
常用元字符:
| 代码 | 说明 |
|------|-------------------|
| .
| 匹配除换行符以外的任意字符 |
| *
| 匹配前面的字符或子表达式零次或多次 |
| \w
| 匹配字母或数字或下划线或汉字 |
| \s
| 匹配任意的空白符 |
| \d
| 匹配数字 |
| \b
| 匹配单词的开始或结束 |
| ^
| 匹配字符串的开始 |
| $
| 匹配字符串的结束 |
\b
代表着 单词的开头或结尾,也就是单词的分界处 ,
通常英文的单词是由空格,标点符号或者换行来分隔的,但是\b并不匹配这些单词分隔字符中的任何一个,它只匹配一个位置。
他代表精确查找 ,如果你想查找he
,有的单词里包含了he
,比如:hello
、head
、here
,
如果你只想精确的查找到he
,你就可以这样写:\bhe\b
.
表示匹配除换行符以外的任意字符
*
表示匹配前面的子表达式零次或多次
如果你的he
单词后面的不远处跟着xi
,你可以这样用:\bhe\b.*\bxi\b
这里*
定义了前面的.
可以是零次或多次
^
表示匹配字符串的开始
$
表示 匹配字符串的结束
这和\b
有点类似
示例:
^abc
:匹配所有以 abc
开始的字符串 (例如:abc
,abcxxx
)
abc$
:匹配所有以abc
结尾的字符串 (例如:abc
,xxxabc
)
^abc$
:匹配开始和结尾都为abc
的字符串 (例如:abc
)
如果什么都不加的话,则匹配所有,如:
abc
:没有任何字符,匹配任何包含abc
的字符串 (例如:aaaabccc
,abc123
,12abc65
)
\w
、\d
、\s
,如果理解了上面几个的话,这几个就比较好理解了
示例:
\bh\w*\b
他表示匹配以字母h
开头的单词-->先是某个单词开始处\b
,然后是字母h
,然后是任意数量的字母或数字\w*
,最后是单词结束处\b
1\d\d\d\d\d\d\d\d\d\d
他表示的就是以数字1
开头的11位的手机号(好像只有1开头的手机号),当然也可以写成1\d{10}
,后面会说
\s
没什么好说的,就是匹配空白符,比如你输入一串英文,然后你换行了,或者使用空格键或者Tab键,你就可以使用\s
反义 {#%E5%8F%8D%E4%B9%89}
有时需要查找不属于某个能简单定义的字符类的字符。
比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
| 代码\语法 | 说明 |
|--------|-----------------------|
| \W
| 匹配任意不是字母,数字,下划线,汉字的字符 |
| \S
| 匹配任意不是空白符的字符 |
| \D
| 匹配任意非数字的字符 |
| \B
| 匹配不是单词开头或结束的位置 |
示例:
[^x]
:匹配除了x
以外的任意字符
[^aeiou]
:匹配除了aeiou
这几个字母以外的任意字符
\S+
:匹配不包含空白符的字符串。
a[^>]+>
:匹配用尖括号括起来的以a开头的字符串。
字符转义 {#%E5%AD%97%E7%AC%A6%E8%BD%AC%E4%B9%89}
如果你想查找元字符本身的话,比如你查找.
或者*
,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。
这时你就得使用\
来取消这些字符的特殊意义 。
因此,你应该使用\.
和\*
。当然,要查找\
本身,你也得用\\
例如:
www\.baidu\.com
匹配 www.baidu.com
E:\\file
匹配 E:\file
重复 {#%E9%87%8D%E5%A4%8D}
常用限定符:
| 代码/语法 | 说明 |
|---------|----------|
| *
| 重复零次或更多次 |
| +
| 重复一次或更多次 |
| ?
| 重复零次或一次 |
| {n}
| 重复n次 |
| {n,}
| 重复n次或更多次 |
| {n,m}
| 重复n到m次 |
上面已经说过了*
,所以这里就不难理解了
示例:
\bh\w*\b
他表示匹配以字母h
开头的单词-->先是某个单词开始处\b
,然后是字母h
,然后是任意数量的字母或数字\w*
,最后是单词结束处\b
\bh\w+\b
他表示匹配以字母h
开头的单词-->先是某个单词开始处\b
,然后是字母h
,然后是一次或多次的字母或数字\w+
,最后是单词结束处\b
第一种情况可以是h
,而第二种情况就不能是h
,后面必须跟上别的
至于?
,就只能是h
,或者h
后面再加一个字符,不能加多
^\d{9}$
表示匹配9位数的数字,比如我的QQ号,996597002,这里指定了位数9,所以必须是9位
可以这样写^\d{5,12}$
,表示匹配 5~12 位的数字,而^\d{5,}$
表示数字的位数,至少是5位或更多次
字符类 {#%E5%AD%97%E7%AC%A6%E7%B1%BB}
这里就不列表了,直接上例子:
|
表示或
例如:a|b
:表示一个字符串里有 a
或者 b
(例如:a
,b
,ab
,abc
)
符号[
和]
定义了一个字符集合,可以匹配[]
之中的任意一个成员文本。
例如:
[abc]
可以匹配a
、b
或c
[.?!]
可以匹配标点符号(.或?或!)[0-9]
代表的含意与\d
完全一致[^abc]
任何字符,除了a
、b
或c
(否定)[a-zA-Z]
a
到z
或A
到Z
,两头的字母包括在内(范围)[a-d[m-p]]
a
到d
或m
到p
:[a-dm-p]
(并集)[a-z&&[def]]
d
、e
或f
(交集)[a-z&&[^bc]]
a
到z
,除了b
和c
:[ad-z]
(减去)[a-z&&[^m-p]]
a
到z
,而非m
到p
:[a-lq-z]
(减去)
来个复杂的表达式:\(?0\d{2}[) -]?\d{8}
这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455,或 02912345678等
分析:首先是一个转义字符\(
,它能出现0次或1次?
,然后是一个0,后面跟着2个数字\d{2}
,然后是)
或-
或空格
中的一个,它出现1次或不出现?
,最后是8个数字\d{8}
。
分组和分支 {#%E5%88%86%E7%BB%84%E5%92%8C%E5%88%86%E6%94%AF}
分组主要是括号的使用
分组和分支结构
在分支结构中,括号是用来表示一个整体的,比如要匹配下面的字符串
I love JavaScript
I love Express
可以用:/^I love (JavaScript|Express)$/
,而不是:/^I love JavaScript|Express$/
表示一个整体还比如 /(abc)+/
一个或者多个 abc
字符串
上面这些使用括号包起来的地方就叫做分组
'I love JavaScript'.match(/^I love (JavaScript|Express)$/)
// ["I love JavaScript", "JavaScript", index: 0, input: "I love JavaScript"]
输出的数组第二个元素,JavaScript
就是分组匹配到的内容
引用分组 {#%E5%BC%95%E7%94%A8%E5%88%86%E7%BB%84}
提取数据
比如我们要用正则来匹配一个日期格式,yyyy-mm-dd
,
可以写出简单的正则/\d{4}-\d{2}-\d{2}/
,这个正则还可以改成分组形式的/(\d{4})-(\d{2})-(\d{2})/
这样我们可以分别提取出一个日期的年月日,用 String 的 match
方法或者用正则的 exec
方法都可以
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2019-09-27";
console.log( string.match(regex) );
// => ["2019-09-27", "2019", "09", "27", index: 0, input: "2019-09-27"]
也可以用正则对象构造函数的全局属性 $1 - $9
来获取
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2019-09-27";
regex.test(string); // 正则操作即可,例如
//regex.exec(string);
//string.match(regex);
`console.log(RegExp.$1); // "209"
console.log(RegExp.$2); // "09"
console.log(RegExp.$3); // "27"
`
替换
如果想要把 yyyy-mm-dd
替换成格式 mm/dd/yyyy
应该怎么做。
String 的 replace
方法在第二个参数里面可以用 $1 - $9
来指代相应的分组
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2019-09-27";
var result = string.replace(regex, "$2/$3/$1");
console.log(result); // "09/27/2019"
等价
var result = string.replace(regex, function() {
return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;
});
console.log(result); // "09/27/2019"
等价
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2019-09-27";
var result = string.replace(regex, function(match, year, month, day) {
return month + "/" + day + "/" + year;
});
console.log(result); // "09/27/2019"
反向引用 {#%E5%8F%8D%E5%90%91%E5%BC%95%E7%94%A8}
匹配日期的正则在使用的时候有好几种写法,例如:
2019-09-27
2019/09/27
2019.09.27
要匹配这三种应该怎么写正则,第一反应肯定是把上面那个正则改一下/(\d{4})[-/.](\d{2})[-/.](\d{2})/
,把 -
改成 [-/.]
这三种都可以
看上去没问题,我们多想想就会发现,这个正则把 2019-09.27
这种字符串也匹配到了,这个肯定是不符合预期的。
这个时候我们就需要用到反向引用了,反向引用可以在匹配阶段捕获到分组的内容 /(\d{4})([-/.])(\d{2})\2(\d{2})/
如果出现括号嵌套,那么嵌套的括号以左括号为准
如果在正则里面引用了前面不存在的分组,这个时候正则会匹配字符本身,比如\1
就匹配\1
贪婪与惰性 {#%E8%B4%AA%E5%A9%AA%E4%B8%8E%E6%83%B0%E6%80%A7}
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符
例如:a.*b
,它将会匹配最长的以a开始,以b结束的字符串
如果用它来搜索aabab
的话,它会匹配整个字符串aabab
。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符 。
前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?
。这样.*?
就意味着匹配任意数量的字符,但是在能使整个匹配成功的前提下使用最少的重复。
例如:a.*?b
匹配最短的,以a
开始,以b
结束的字符串。如果把它应用于aabab
的话,它会匹配aab
(第一到第三个字符)和ab
(第四到第五个字符)。
懒惰限定符:
| 代码/语法 | 说明 |
|----------|------------------|
| *?
| 重复任意次,但尽可能少重复 |
| +?
| 重复1次或更多次,但尽可能少重复 |
| ??
| 重复0次或1次,但尽可能少重复 |
| {n,m}?
| 重复n到m次,但尽可能少重复 |
| {n,}?
| 重复n次以上,但尽可能少重复 |
其他的就不说了,大同小异
整理的不好,多多包涵
最后给大家推荐一个很强大的正则网站:https://regex101.com/
常用数字正则校验 {#%E5%B8%B8%E7%94%A8%E6%95%B0%E5%AD%97%E6%AD%A3%E5%88%99%E6%A0%A1%E9%AA%8C}
验证数字:^[0-9]*$
验证n位的数字:^\d{n}$
验证至少n位数字:^\d{n,}$
验证m-n位的数字:^\d{m,n}$
验证零和非零开头的数字:^(0|[1-9][0-9]*)$
验证有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
验证有1-3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
验证非零的正整数:^\+?[1-9][0-9]*$
验证非零的负整数:^\-[1-9][0-9]*$
验证非负整数(正整数 + 0) ^\d+$
验证非正整数(负整数 + 0) ^((-\d+)|(0+))$
验证长度为3的字符:^.{3}$
验证由26个英文字母组成的字符串:^[A-Za-z]+$
验证由26个大写英文字母组成的字符串:^[A-Z]+$
验证由26个小写英文字母组成的字符串:^[a-z]+$
验证由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
验证由数字、26个英文字母或者下划线组成的字符串:^\w+$
验证用户密码:^[a-zA-Z]\w{5,17}$ 正确格式为:以字母开头,长度在6-18之间,只能包含字符、数字和下划线。
验证是否含有 ^%&',;=?$\" 等字符:[^%&',;=?$\x22]+
验证汉字:^[\u4e00-\u9fa5]*$
验证Email地址:^\w+[-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
验证InternetURL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ ;^[a-zA-z]+://(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$
验证电话号码:^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$:--正确格式为:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX。
验证身份证号(15位或18位数字):^\d{15}|\d{}18$
验证一年的12个月:^(0?[1-9]|1[0-2])$ 正确格式为:"01"-"09"和"1""12"
验证一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 正确格式为:01、09和1、31。
整数:^-?\d+$
非负浮点数(正浮点数 + 0):^\d+(\.\d+)?$
正浮点数 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
非正浮点数(负浮点数 + 0) ^((-\d+(\.\d+)?)|(0+(\.0+)?))$
负浮点数 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数 ^(-?\d+)(\.\d+)?$