正则对象
正则表达式又称规则表达式(Regular Expression
)。RegExp
。常用于检索匹配替换符合规则的文本。
JavaScript 对他进行了本地化实现。
正则表达式是对字符串的操作逻辑匹配,可以匹配一个或者多个字符串
正则表达式又多个核心的功能: 匹配是否满足条件,获取想要的部分
JavaScript 中正则对象的字面量写法是/原始正则表达式/
生成正则表达式的方式:
let reg1 = /asd/g //字面量写法,g是修饰符
let reg2 = new RegExp(/asd/g) //也是字面量写法
let reg3 = new RegExp("asd", "g") //匹配方法 匹配模式(修饰符)
相关方法
正则表达式是一个对象,具有test
和exec
方法,test
是测试前面的正则表达式在后面找得到,就返回true
,否则就返回false
:
typeof /asd/ //object
;
/as/.test("asd") //true
;
/asd/.test("assd") //false
在exec
中匹配到了就会返回一个数组:
;
/asd/.exec("asd") //["asd", index: 0, input: "asd", groups: undefined]
;
/asd/.exec("assd") //null
数组对象中第一项是第一个满足匹配的字符串,第二项的是满足匹配开始的下标。第三项是被匹配的输入。groups
是命名捕获组。
字符串String具有
match
replace
search
split
> "asd".match("as");
["as", index: 0, input: "asd", groups: undefined] >
"asd".match(/as/);
["as", index: 0, input: "asd", groups: undefined]
//没有就是null
>
"asd".replace(/as/, "sa");
"sad"
//不会改变原字符串,没匹配就不变
>
"asd".search(/dd/); -
1
//返回第一个匹配的位置下标,没有就-1
>
"asd".search(/sd/);
1
>
"asd".split(/s/);
["a", "d"];
修饰符
JavaScript 中,正则表达式的字面量具备修饰符 i
和 g
和 m
和 u
修饰符是写到正则匹配的第二个斜杠后面,表示前面的表达式匹配的一些设置
i
对大小写不敏感,可以无视大小写匹配
> /a/i.test("AAA");
true
>
/a/.test("AAA");
false
g
全局匹配,不在第一次匹配后停止,继续向后匹配
> "asdaassddaaddss".match(/aa/);
["aa", index: 3, input: "asdaassddaaddss", groups: undefined] > //只匹配到了第一个。
undefined
>
"asdaassddaaddss".match(/aa/g);
["aa", "aa"]
m
多行匹配,将具有换行的字符串(\n)每行单独匹配
"asd\nasdf".match(/d$/gm) //["d"];
"asd\nasdf".match(/d$/g) //null;
u
unicode 匹配模式,能识别 unicode 标识符。{}前面必须加上\u 表示识别 unicode 编码
;
/\u{61}/.test("a") //false
;
/u{61}/u.test("a") //false
;
/\u{61}/u.test("a") //true
元字符
正则表达式的特殊字符
\
转义字符,将特殊字符转换成普通字符 比如 new RegExp(/\//)
;
/\\/.test("d") //false,前面是匹配没有转义的\ 后面的\d被转义了
;
/\\/.test("\\d") //true,前面是匹配没有转义的\ 后面的\d没有转义
\w
单个任意普通字符,等价于[0-9A-z_]
"fsd".match(/\w/) //["f", index: 0, input: "fsd", groups: undefined]
\W
单个任意非字符,等价于[^0-9A-z_]
\d
任意单个数值,等价于[0-9]
\D
任意单个非数值,等价于[^\d]
\s
任意空格的内容,等价于[\t\n\r\v\f ]
,包含了空格和等价于空格的内容(空格 制表符 回车 换行 垂直换行 换页)
\S
等价于[^\s]
\b
匹配单词边界的位置
"abfd fgh jkl".match(/\bf/) //["f", index: 5, input: "abfd fgh jkl", groups: undefined]
"abfd fgh jkl".match(/h\b/) //["h", index: 7, input: "abfd fgh jkl", groups: undefined]
此时 fgh 的 f 在单词边界,所以满足匹配
\B
匹配非单词边界
^
匹配开始输入是不是相关字符
;
/^asd/.test("asmdasd") //false
;
/^asd/.test("asdqwe") //true
$
匹配是不是以相关字符结束
;
/asd$/.test("qwerasd") //true
;
/^a$/.test("aaa") //false
;
/^a$/.test("a") //true 以a开始并且以这个a结束
;
/^aa$/.test("aasa") //true
量词
{a,b}
匹配前面的字符最少 a 次最多 b 次
{a}
匹配前面的字符 a 次,不多不少
{a,}
匹配前面的字符至少 a 次,可多
"asasssassdd".match(/as{1,3}/g) //["as", "asss", "ass"]
"asasssassdd".match(/as{3}/g) //["asss"]
*
匹配前面的字符 0 次或多次
等价于{0,}
"asasd".match(/a*/) //["a", index: 0, input: "asdasd", groups: undefined]
"asdasd".match(/b*/) //["", index: 0, input: "asdasd", groups: undefined] 匹配了0次
+
匹配前面的字符 1 次或多次
等价于{1,}
"asdasd".match(/b+/g) //null
"asdaasd".match(/a+/g) //["a", "aa"]
?
匹配前面的字符 0 次或 1 次
等价于{0,1}
"aassddasdf".match(/da?/g) //["d", "da", "d"]
"nice! nice to meet you".match(/nice!?/g) //["nice!", "nice"]
惰性匹配
我们发现,当量词数量不唯一的时候,正则匹配会默认以贪心模式匹配。尽可能匹配多的元素
javascript"haaaaaaaahaaahaaha".match(/ha+/g) //["haaaaaaaa", "haaa", "haa", "ha"]
在量词后面添加惰性量词,他就会尽可能匹配少的元素
javascript"haaaaaaaahaaahaaha".match(/ha+?/g) //["ha", "ha", "ha", "ha"] "ha??? who??? are you??".match(/a\???/g) //?转义 a后面的"?"有{0,1}但是尽可能少的匹配
字母和数值以及范围: [a-z]等
[a-z]
等价于
"asd123asd".match(/[a-d]/g) //["a", "d", "a", "d"] a,b,c,d
"asd123asd".match(/[a-zA-Z]/g) //["a", "s", "d", "a", "s", "d"]
//匹配字母,等同于下面,不区分大小写
[0-9]
等价于
"asd123asd".match(/[0-9]/g) //["1", "2", "3"]
//数值等价于\d
"asd123asd".match(/\d/g) //["1", "2", "3"]
"Asd123asd".match(/^[a-z]/gi) //["A"]
"asdfghjkl".match(/[^asd]/g) //["f", "g", "h", "j", "k", "l"]
[^xyz]
反向匹配,不是范围内的元素
"Asd123asd".match(/[^a-z]/gi) //["1", "2", "3"]
[\u4e00-\u9fa5]
,任意汉字
"大as家12 3_?好!".match(/[\u4e00-\u9fa5]/) //["大", "家", "好"]
分组
js 不支持命名分组,固化分组。
(...)
匹配并获取匹配(pattern),获取支持 replace 第二个参数"$1"
"$2"
等通常用于 replace 时,第二个参数可以用
$1
$2
来指代你获取的元素,方便替换(?:...)
可以分组不获取匹配
//将任意中文后面的全角"!"替换成英文的"!"
>
"你好啊!我很高兴!asd!".replace(/([\u4e00-\u9fa5])!/g, "$1!")
"你好啊!我很高兴!asd!"
事实上,replace 可以接受函数,函数的形参指代被匹配的字符串:
//2048游戏合并单行
function foo(arr) {
const s = arr.filter((v) => v !== 0).join(",")
return (s.replace(/(\d+),\1/g, (w) => w[0] << 1) + ",0,0,0,0")
.split(",")
.map((v) => 1 * v)
.slice(0, 4)
}
console.log(foo([64, 128, 2, 2]))
- (|)与[]中的|等价。从左往右只要有一个满足任意条件即匹配
重复出现
\1
前一个分组多重复一次
\1\1
前一个分组重复 3 次
(\d)\1{2}
一个数字重复 3 次
断言
匹配某个字符串,前提是前面或者后面必须满足条件(?),都为非获取
- (?=pattern) 正向肯定,如果后面有,那么匹配成功
- (?!pattern) 正向否定,如果后面没有,那么匹配成功
"asd123asd12".match(/asd(?!123)/g) //["asd"] 这是第二个asd
"asd123asd12".match(/asd(?=123)/g) //["asd"] 这是第二个asd
;
`asd123
Asd123
aSd321`.match(/^(?!Asd).*/gm) //匹配不以Asd开头的行["asd123", "aSd321"]
- (?<=pattern) 反向肯定,如果前面有,那么匹配成功,要写到前面
"asdd123asd12".match(/(?<=123)asd/g) //匹配前面有123的asd,也就是第二个["asd"]
- (?<!pattern) 反向否等,如果前面没有,那么匹配成功
"book.js,book1.js,book.css".match(/(?<!book)\.js/g) //匹配第二个js
很多书本上,断言也叫做环视、预查。