1 正则相关属性和方法
1.1 lastIndex属性
当作为正则表达式对象的方法使用时,要特别注意它的lastIndex属性。
lastIndex从字面上来讲就是最后一个索引,实际上它的意思是正则表达式开始下一次查找的索引位置,第一次的时候总是为0的。
非全局模式lastIndex属性 不生效
1.2 匹配方法test()
Regex.test(str);
当正则在全局模式下使用test方法时需要注意一个问题 例子如下:
var re=/[a-z]\d/g;
console.log(re.lastIndex)//0
console.log(re.test('a1b2c3'))//true
console.log(re.lastIndex)//2
console.log(re.test('a1b2c3'))//true
console.log(re.lastIndex)//4
console.log(re.test('a1b2c3'))//true
console.log(re.lastIndex)//6
console.log(re.test('a1b2c3'))//false
console.log(re.lastIndex)//0
console.log(re.test('a1b2c3'))//true
由于lastIndex总是指向下一次查找开始的地方,在第三次判断的时候lastIndex已经为6了,所以为false;
1.3 提取匹配项 match()
let ourStr = "Regular expressions";
let ourRegex = /expressions/;
ourStr.match(ourRegex); //["expressions"]
.match
语法是目前为止一直使用的 .test
方法中的“反向”:
'string'.match(/regex/);
/regex/.test('string');
2 重点标识
2.1 修饰符
i ———— 忽略大小写的标志 例:/ignorecase/i
g ———— 全局匹配 例:/ignorecase/g
m ———— 多行匹配 例:
let str = "@123
@456
@789
"
str.replace(/@\d/g,'x')
/*"x23
@456
@789
"*/
//因为有换行符的存在所以下面@不能算作字符串的开头
str.replace(/@\d/gm,'x')
/*"x23
x456
x789
"*/
//这时候m就派上用处了
2.2 范围类
[]———— 字符集 例:/b[aiu]g/
只能匹配bag big bug
- ———— 连字符 例:
/[a-e]at/
要匹配小写字母a
到e
,可以使用[a-e]
,数字同理 两者还能同时使用 例:/[a-z0-9]/ig
2.3 预定义类
. ———— 通配符 例:/.un/
可以匹配run gun等;等价类为[^\r\n],除了回车符和换行符之外的所有字符。
\w ———— 等同于[A-Za-z0-9_]
单词字符(字母、数字下划线)
\W ———— 等同于[^A-Za-z0-9_]
非单词字符
\d ———— 等同于[0-9]
数字字符
\D ———— 等同于[^0-9]
非数字字符
\s ———— 空白符。此匹配模式将匹配空格、回车符、制表符、换页符和换行符;似于元字符 [ \r\t\f\n\v]
。
\S ———— 非空白符。此匹配模式将匹配空格、回车符、制表符、换页符和换行符;似于元字符 [ \r\t\f\n\v]
。
2.4 边界字符
^ ———— 以xxx开始 例:/[^aeiou]/gi/
这是一个不想匹配的字符集合 ,这里只不匹配元音字符,字符 .
、!
、[
、@
、/
和空白字符等也会被匹配
字符^的另外一个作用是匹配字符串的开头 如:
let firstString = "Ricky is first and can be found.";
let firstRegex = /^Ricky/;
let secondString = "icky is first and can be found.";
console.log(firstRegex.test(firstString))//true
console.log(firstRegex.test(secondString)) //false
$ ———— 以xxx结束。 例:
let theEnding = "This is a never ending story";
let storyRegex = /story$/;
storyRegex.test(theEnding);//true
let noEnding = "Sometimes a story will have to end";
storyRegex.test(noEnding);//false
\b ———— 单词边界
\B ———— 非单词边界
2.5 量词
?———— 出现一次或零次。 可以将此符号视为前面的元素是可选的。例:
let american = "color";
let british = "colour";
let rainbowRegex= /colou?r/;
rainbowRegex.test(american);//true
rainbowRegex.test(british);//true
- ———— 匹配一次或者连续多次的的字符(至少出现一次) 例:
/a+/g
会在abc
中匹配到一个匹配项,并且返回["a"]
。 因为+
的存在,它也会在aabc
中匹配到一个匹配项,然后返回["aa"]
。
- ———— 出现零次或多次(任意次) 例:
/go*/
可以匹配出现零次或多次的字符 具体示例如下:
let soccerWord = "gooooooooal!";
let gPhrase = "gut feeling";
soccerWord.match(goRegex); //["goooooooo"]
gPhrase.match(goRegex); //["g"]
{n} ———— 出现n次。例,要匹配出现 3
次字母 a
的在字符串 ah
,正则表达式应为/a{3}h/
。
{n,m} ———— 出现n到m次 例:
let A4 = "aaaah";
let A2 = "aah";
let multipleA = /a{3,5}h/;
multipleA.test(A4);//true
multipleA.test(A2);//false
{n,} ———— 至少出现n次。例:匹配至少出现 3
次字母 a
的字符串 hah
,正则表达式应该是 /ha{3,}h/
。
{,m} ———— 最多出现m次。
2.6 非贪婪模式
正则默认是贪婪模式
?———— 懒惰匹配(非贪婪模式) 例:/t[a-z]*i/
应用于字符串 "titanic"
。 这个正则表达式是一个以 t
开始,以 i
结束,并且中间有一些字母的匹配模式。正则表达式默认是贪婪匹配,因此匹配返回为 ["titani"]
。 它会匹配到适合该匹配模式的最大子字符串。以使用 ?
字符来将其变成懒惰匹配。 调整后的正则表达式 /t[a-z]*?i/
匹配字符串 "titanic"
返回 ["ti"]
。
2.7 分组
分组需要使用()
具体例子如何
//分组前
'a1b2c3d4'.replace(/[a-z]\d{3}/g,'x');//a1b2c3d4
//分组后
'a1b2c3d4'.replace(/([a-z]\d){3}/g,'x');//xd4
2.8 或
使用 | 可以达到或的效果
'DeanWinnie'.replace(/Dean|Winnie/g,'x')//xx
'DeanDenise'.replace(/De(an|nise)/g,'x')//xx
2.9 反向引用
用$加数字来代表各个分组 需要配合分组使用 不然是无效的具体例子如下
"2022-02-22".replace(/(\d{4})-(\d{2})-(\d{2})/,'$2/$3/$1')//02/22/2022
2.10 忽略分组
不希望捕获的分组,只需要在分组内加上?:就可以了 例如
'deanwinnie'.replace(/(?:dean)(winnie)/,'$1$2')//winnie$2 这时候只存在分组1,且分组1为winnie
2.11 前瞻
前瞻就是在正则表达式匹配到规则的时候,向前检查是否复核断言,
(?=…) ———— 正向前瞻即正向先行断言,正向先行断言会查看并确保搜索匹配模式中的元素存在,但实际上并不匹配。例:
let quit = "qu";
let qua = 'qa'
let quRegex= /q(?=u)/;
quit.match(quRegex);//true
qua.match(quRegex);//false
(?!..)————负向前瞻即负向先行断言**。**希望不存在的匹配模式。 如果负向先行断言部分不存在,将返回匹配模式的其余部分。例:
let quit = "qu";
let noquit = "qt";
let qRegex = /q(?!u)/;
quit.match(qRegex);//false
noquit.match(qRegex);//true
3 练习题
3.1 限制可能的用户名
- 用户名只能是数字字母字符。
- 用户名中的数字必须在最后。 数字可以有零个或多个。 用户名不能以数字开头。
- 用户名字母可以是小写字母和大写字母。
- 用户名长度必须至少为两个字符。 两位用户名只能使用字母。
//方案一
let userCheck = /^[a-z][a-z]+\d*$|^[a-z]\d\d+$/i;
代码解读
^
输入开始[a-z]
第一个字符是一个字母[a-z]+
后面的字符是字母\d*$
输入以 0 位或更多位数字结尾|
或者^[a-z]
第一个字符是一个字母\d\d+
以下字符为 2 位或更多位$
输入结束
//方案二
let userCheck = /^[a-z]([0-9]{2,}|[a-z]+\d*)$/i;
^
输入开始[a-z]
第一个字符是一个字母[0-9]{2,0}
以两个或多个数字结尾|
或者[a-z]+
接下来有一个或多个字母\d*
并以零个或多个数字结尾$
输入结束i
忽略输入的大小写