让你学懂正则表达式(1)
作者:GrayRabbit 时间:2021.11.3
概述
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。——百度百科
简单说正则表达式就是一个对于字符串匹配规则,但是不同于大家所普遍认为的匹配字符串只是对字符匹配,其实正则表达式也可以对位置进行匹配(有些时候甚至更重要?)。如果还迷糊,不要急,下面灰兔将详细介绍字符与位置的匹配方法。
字符匹配
1.精确匹配
/javascript/
上面的正则表达式可以精确的匹配一个字符串中的“javascript”子串。但是如果正则表达式只能进行这种匹配似乎并没有多厉害呀?没错,正则表达式的强大之处在于它可以模糊匹配。
2.模糊匹配
在说模糊匹配之前先介绍两个东西量词
和字符组
。
量词:用来描述某个字符(字符组)重复出现的次数的规则。
字符组:用来描述可以匹配的字符的合集的规则。
我们可以很直观的可以感受到,量词是用来横向的向前拓展,而字符组是用来纵向的展开。那么我们应该如何使用呢?
首先介绍量词最基本的写法{n,m}
,其表示匹配前面的字符(字符组)最少n次,最多m次。例如:
/^a{2,6}$/
a ×
aa √
aaaaaa √
aaaaaaa ×
这个正则表达式,它表示匹配a最少2次,最多6次,其中^
和$
代表这个字符串的前面就是开头和这个字符串的接下来就是结尾(也就是说字符串整体匹配),下面会详细介绍,这里先了解就行。
量词还有其他的形式:
- {n}:匹配精确n次。
- {n,}:匹配至少n次,没有上限。
- {n,m}:匹配最少n次,最多m次。
- ?:匹配0或1次,作用等同于{0,1}。
- *:匹配至少0次,没有上限,作用等同于{0,}。
- +:匹配至少1次,没有上限,作用等同于{1,}。
- 前面的规则紧着加个?,如+?,{2,6}?,表示惰性匹配,即匹配达到最小次数就开始匹配下个字符。(默认情况是贪婪的)
没有{,m}这种写法!!!!!!!
量词只作用于前一个字符或者前面一个规则(括号,字符组等),而不是前面整个字符串!!!!!
几个例子:
/^ab?$/
a √ ab √ abb × b最多可以重复1次
/^ab+$/
a × b至少要重复一次 ab √ abbbbbbb √
/^a(ab){1,2}$/
aab √ aabb × 要“ab”整体重复 aabab √
好了,我们已经学会了横向的拓展,下面我们来使用字符组来进行纵向的展开。
还是介绍最基本的写法[abc]
,它代表匹配a或者b或者c。让我们配合前面的量词来个综合练习:
/^[abc]{2,}$/
a x 至少匹配2次,且每次为a或b或c
ac √
abc √
aaaaabbbbbcccc √
abcd × 只能匹配a或者b或者c,有d不符合规则
这个正则表达式匹配这样字符串,它开头与结尾之前是由a或者b或者c组成的长度至少为2的字符串。
字符组还有下面这些形式:
- [char1-char2] : 表示匹配char1和char2以及它们之间的字符,如[1-5]等于[12345],[a-d]等于[abcd],[A-D]等于[ABCD]。
- 除了1情况下的字符组中的- :表示匹配
-
这个字符,如/[abc-]{2,}/可以匹配ab-c,------,abc-等。 - [^] : 开头加个
^
表示反向范围(注意^和[紧挨着),如[^a-z] 可以匹配除小写字母外的字符。 - \d :等于[0-9]。
- \D :等于*[^0-9]*。
- \w :等于[0-9a-zA-Z_],匹配数字、大小写字母和下划线。
- \W :等于[^0-9a-zA-Z_]。
- \s : 等于[ \t\v\n\r\f],匹配空格、水平制表符、垂直制表符、换行符、回车符、换页符。
- \S :等于[^\t\v\n\r\f]。
- . : 等于[^\n\r\u2028\u2029]。通配符,匹配几乎任意字符。
- [^] :真正的匹配所有字符。
/^[a-c]{2,}$/
a x 至少匹配2次,且每次为a或b或c ac √ abc √ aaaaabbbbbcccc √ abcd × 只能匹配a或者b或者c,有d不符合规则
/^\d+$/
123 √ 12312a ×只能匹配数字
/^[^a-z]+$/
123 √ 12312a ×有小写字母a
3.分支匹配
如果同一个部分有多种可能的规则怎么办呢,那么就要用到分支匹配了。
具体形式如下:p1|p2|p3 ,其中 p1、p2 和 p3 是子模式,用 |分隔,表示匹配其中任何之一。比如
/^(\d+\.\d+|\d+)$/
42.1 √ 匹配\d+\.\d+ 即数字小数点数字
43 √ 匹配\d+
43a × 全都不匹配
4.小作业:
- 写一个正则表达式,它可以匹配颜色的 #rgb 这种形式,如#fff #Acb #e3e3e3。
- 写一个正则表达式,它可以匹配 yyyy-mm-dd 这种格式的日期。
- 写一个正则表达式,它可以匹配 xx:xx 格式的时间。
位置匹配
1.什么是位置?
大部分人在利用正则表达式时,可能会忽略位置匹配,位置其实就是字符与字符之间的间隙,比如上面遇到的^
代表的就是字符串第一个字符前的位置,$
就是字符串最后一个字符后面的位置,下图红色箭头指的都叫做位置,用来匹配位置的叫做锚。
2.怎么匹配位置
一共有8种锚,除了上文说的^
和$
,还有\b
,\B
,(?=p)
,(?!p)
,(?<=p)
和(?<!p)
。
下面我们来详细的介绍下:
1. ^ 起始 $ 结尾
^表示匹配单行模式下第一个字符的前面,多行模式下各行的开头。类似的,$表示匹配单行模式下最后个字符的后面,多行模式下各行的结尾。如:
"abcaa".replace(/^a/g,"123") === "123bcaa"
"abcaa".replace(/a/g,"123") === "123bc123123"
"abcaa".replace(/^bc/g,"123") === "abcaa"
"abcaa".replace(/bc/g,"123") === "a123aa"
"abcaa".replace(/a$/g,"123") === "abca123"
"abcaa".replace(/a/g,"123") === "123bc123123"
"abcaa".replace(/bc$/g,"123") === "abcaa"
"abcaa".replace(/bc/g,"123") === "a123aa"
第一个会匹配前面是开头的字符a,因此会匹配到第一个a,替换后就是"123bcaa"。
第三个虽然字符串中有bc,但前面并不是开头,所以不会被替换。
第五个会匹配后面是结尾的字符a,因此会匹配到最后一个a,替换后就是"abca123"。
第七个虽然字符串中有bc,但后面并不是开头,所以不会被替换。
2. \b 单词边界 \B非单词边界
\b表示\w和\W,^,$之间的位置。类似的\B表示\W和\w,^,$之间的位置,就是所有位置减去\b的位置。比如:
"hello world!".replace(/\b/g,"&") === "&hello& &world&!"
"hello world!".replace(/\B/g,"&") === "h&e&l&l&o w&o&r&l&d!&"
"hello world!".replace(/\bh/g,"&") === "&ello world!"
"hello world!".replace(/\b|\B/g,"&") === "&h&e&l&l&o& &w&o&r&l&d&!&"
第一二个不多解释,注意的是它们的合正好就是所有位置,4可以验证。
第三个表示字符边界位置后面还要紧跟着一个h,符合的显然就只有第一个字母h。
3. (?=p) 正向先行断言 (?!p) 负向先行断言 (?<=p) 正向后行断言 (?<!p) 负向后行断言
正向先行断言表示后面是p的位置,负向先行断言表示后面不是p的位置,正向后行断言表示前面是p的位置,负向后行断言表示前面不是p的位置。其中前两个的合是所有位置,后两个的合是所有位置。比如:
"hello world!".replace(/(?=l)/g, "&") === "he&l&lo wor&ld!"
"hello world!".replace(/(?!l)/g, "&") === "&h&ell&o& &w&o&rl&d&!&"
"hello world!".replace(/(?!l)|(?=l))/g, "&") = "&h&e&l&l&o& &w&o&r&l&d&!&"
"hello world!".replace(/(?<=l)/g, "&") === "hel&l&o worl&d!"
"hello world!".replace(/(?!l)/g, "&") === "&h&e&llo& &w&o&r&ld&!&"
"hello world!".replace(/(?<!l)|(?<=l))/g, "&") === "&h&e&l&l&o& &w&o&r&l&d&!&"
如果我们想把数字变成每三位用逗号分隔,就可以这样写:
"100000000".replace(/(?!^)(?=(\d{3})+$)/g, ",") === "100,000,000"
首先这个位置不能是开头,其次这个位置到结尾之前的数字的个数正好是3的大于等于1倍个。
3.位置的特性
字符之间的位置可以被无限选中,如:
"hello world!".replace(/^(?=h)/g, "&") === "&hello world!"
很明显,两个位置同时选中了开头的位置。
4.小作业
-
写一个正则表达式,使得可以用replace将一个句子 每个字母的开头前 加入一个符号。
-
写一个正则表达式,使得可以用replace将一个句子 每个字母的结尾后 加入一个符号。
结语
至此为止,我们已经可以利用正则表达式做绝大部分东西啦,可以关注下博主蹲下面的更新哦。