正则表达式专题
创建正则表达式:
regexp = new RegExp("pattern", "flags");
或者(但底下的不允许插入${}模版字符串)
regexp = /pattern/; // 没有修饰符
regexp = /pattern/gmi; // 带有修饰符 g、m 和 i
在js中使用正则表达式,会有两个方法:
str.match(regexp)
方法在字符串 str
中寻找 regexp
的所有匹配项。
str.replace(regexp, replacement)
方法使用 replacement
替换在字符串 str
中找到的 regexp
的匹配项(如果带有修饰符 g
则替换所有匹配项,否则只替换第一个)。
- 正则表达式由模式和可选择修饰符构成:
g
、i
、m
、u
、s
和y
。str.match(regexp)
方法寻找匹配项:如果带有修饰符g
,则会返回所有匹配项,否则只会返回第一个匹配项。str.replace(regexp, replacement)
方法使用replacement
替换regexp
的匹配项:如果带有修饰符g
,则会替换所有匹配项,否则只会替换第一个匹配项。regexp.test(str)
方法用于测试,如果找到至少一个匹配项则返回true
,否则返回false
。
存在以下字符类:
\d
—— 数字。\D
—— 非数字。\s
—— 空格符号,制表符,换行符。\S
—— 除了\s
。\w
—— 拉丁字母,数字,下划线'_'
。\W
—— 除了\w
。.
—— 带有修饰符's'
时匹配任何字符,否则匹配除换行符\n
之外的任何字符。
插入符号
^
和美元符号$
在正则表达式中具有特殊的含义。它们被称为“锚点”。插入符号
^
匹配文本开头,而美元符号$
则匹配文本末尾。
- 要在字面意义上搜索特殊字符
[ \ ^ $ . | ? * + ( )
,我们需要在它们前面加上一个反斜杠\
(“转义它们”)。- 如果在
/.../
内(但不在new RegExp
内),我们还需要转义/
。- 当将字符串传递给给
new RegExp
时,我们需要双反斜杠\\
,因为字符串引号会消耗一个反斜杠。
在方括号
[…]
中的几个字符或者字符类表示“搜索给定字符中的任意一个”。例如,
[eao]
表示以下 3 个字符中的任何一个:'a'
、'e'
或'o'
。// 查找 [t 或 m],然后匹配 "op" alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "top"
量词:{}, *, ?, +
最简单的量词便是大括号中的数字:
{n}
。在一个字符(或一个字符类,或
[...]
等)后附加一个量词,用来指出我们具体需要的数量。要查找 3-5 位的数字,我们可以将限制写在花括号中:
\d{3,5}
+代表“一个或多个”,与
{1,}
相同?代表“零个或一个”,与
{0,1}
相同。换句话说,它使得符号变得可选。例如,模式
ou?r
查找o
,后跟零个或一个u
,然后是r
。*代表“零个及以上”,与
{0,}
相同。也就是说,字符可以出现任何次数或者不出现。例如,
\d0*
查找一个数字后面跟着任意数量的零(可能有很多或没有)的数字:
这么说吧:通常问号
?
本身就是一个量词(0 或 1),但如果将其放到 另一个量词(甚至是它自己)后面,就会有不同的含义 —— 它将匹配的模式从贪婪转为惰性。// 贪婪模式 let regexp = /".+"/g; let str = 'a "witch" and her "broom" is one'; alert( str.match(regexp) ); // "witch" and her "broom" // 惰性模式 let regexp = /".+?"/g; let str = 'a "witch" and her "broom" is one'; alert( str.match(regexp) ); // "witch", "broom"
量词有两种工作模式:
贪婪模式
默认情况下,正则表达式引擎会尝试尽可能多地重复量词字符。例如,
\d+
会消耗所有可能的字符。当无法消耗更多(在尾端没有更多的数字或字符串)时,然后它再匹配模式的剩余部分。如果没有匹配,则减少重复的次数(回溯),并再次尝试。惰性模式
通过在量词后添加问号
?
来启用。正则表达式引擎尝试在每次重复量化字符之前匹配模式的其余部分。惰性模式并不是贪婪搜索的“灵丹妙药”。另一种方式是使用排除项“微调”贪婪搜索,如模式
"[^"]+"
。
模式的一部分可以用括号括起来
(...)
。这被称为“捕获组(capturing group)”。这有两个影响:
- 它允许将匹配的一部分作为结果数组中的单独项。
- 如果我们将量词放在括号后,则它将括号视为一个整体。
alert( 'Gogogo now!'.match(/(go)+/ig) ); // "Gogogo"
括号将正则表达式中的一部分组合在一起,以便量词可以整体应用。
括号组从左到右编号,可以选择用
(?<name>...)
命名。可以在结果中获得按组匹配的内容:
- 方法
str.match
仅当不带修饰符g
时返回捕获组。- 方法
str.matchAll
始终返回捕获组。如果括号没有名称,则匹配数组按编号提供其内容。命名括号还可使用属性
groups
。let dateRegexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/; let str = "2019-04-30"; let groups = str.match(dateRegexp).groups; alert(groups.year); // 2019 alert(groups.month); // 04 alert(groups.day); // 30
我们还可以在
str.replace
的替换字符串中使用括号内容:在左括号后紧跟着放置?<name>
即可完成对括号的命名,通过数字$n
或者名称$<name>
let str = "John Bull"; let regexp = /(\w+) (\w+)/; alert( str.replace(regexp, '$2, $1') ); // Bull, John -------------------------------- let regexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/g; let str = "2019-10-30, 2020-01-01"; alert( str.replace(regexp, '$<day>.$<month>.$<year>') ); // 30.10.2019, 01.01.2020
可以通过在组的开头添加
?:
来排除编号。当我们需要对整个组应用量词,但不希望将其作为结果数组中的单独项时这很有用。我们也不能在替换字符串中引用这样的括号。
选择是正则表达式中的一个术语,实际上是一个简单的“或”。
在正则表达式中,它用竖线
|
表示。方括号只允许字符或字符类。选择允许任何表达式。正则表达式
A|B|C
表示表达式A
、B
或C
其一均可。例如:
gr(a|e)y
等同于gr[ae]y
。gra|ey
表示gra
或ey
。要将选择应用于模式中一部分内容的选择,我们可以将其括在括号中:
I love HTML|CSS
匹配I love HTML
或CSS
。I love (HTML|CSS)
匹配I love HTML
或I love CSS
。
前瞻断言
语法为:
x(?=y)
,它表示“仅在后面是Y
时匹配X
”。这里的X
和Y
可以是任何模式。否定前瞻断言
语法是:
X(?!Y)
,意思是“搜索X
,但前提是后面没有Y
”。
字符串所有的正则方法
str.match(regexp)
方法在字符串str
中查找regexp
的匹配项。方法
str.matchAll(regexp)
是str.match
的“更新、改进”的变体。与
match
相比有 3 个区别:
- 它返回一个包含匹配项的可迭代对象,而不是数组。我们可以用
Array.from
将其转换为一个常规数组。- 每个匹配项均以一个包含捕获组的数组形式返回(返回格式与不带修饰符
g
的str.match
相同)。- 如果没有结果,则返回的是一个空的可迭代对象而不是
null
。str.split(regexp|substr, limit)
使用正则表达式(或子字符串)作为分隔符来分割字符串。
我们可以用
split
来分割字符串,像这样:str.search(regexp)
方法
str.search(regexp)
返回第一个匹配项的位置,如果没找到,则返回-1
:str.replace(str|regexp, str|func)
这是用于搜索和替换的通用方法,是最有用的方法之一。它是搜索和替换字符串的瑞士军刀。
str.replaceAll(str|regexp, str|func)
这个方法与
str.replace
本质上是一样的,但有两个主要的区别:
- 如果第一个参数是一个字符串,它会替换 所有出现的 和第一个参数相同的字符串,而
replace
只会替换 第一个。- 如果第一个参数是一个没有修饰符
g
的正则表达式,则会报错。带有修饰符g
,它的工作方式与replace
相同。regexp.test(str)
方法
regexp.test(str)
查找匹配项,然后返回true/false
表示是否存在。let str = "I love JavaScript"; // 这两个测试相同 alert( /love/i.test(str) ); // true alert( str.search(/love/i) != -1 ); // true