介绍
正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。这些模式被用于
RegExp
的exec
和test
方法, 以及String
的match
、matchAll
、replace
、search
和split
方法。
正则对象
要使用正则表达式,就必须在程序创建
其中,有两种创建方式
正则对象
- 1. 隐式创建
const reg = /\d/gi // 匹配模式/匹配标志
// 动态正则匹配
const regSubstring = '0123456789'.substring(4, 7)
const reg = eval(`/${regSubstring}/g`)
- 2. 直接实例化
/**
* @param {string | RegExp} RegExp 匹配模式
* @param {string} mode 匹配标志
*/
const reg = new RegExp('abcd', 'gi')
// 动态正则匹配
let name1 = "xxx";
const reg1 = new RegExp(name) // /xxx/
let name2 = "xxx\\d";
const reg2 = new RegExp(name) // /xxx\d/
- 3. 区别
const reg = /\d/gi
// 如果直接实例化,那么像"\d"这样的字符,需要转义"\\d"
const reg = new RegExp("\\d","gi")
匹配标志
-
g
lobal: 全局搜索。保留最后一个匹配项的索引,允许迭代搜索。 -
case
i
nsensitive: 忽略大小写。 使整个表达式不区分大小写。 -
m
ultiline: 多行。 起点/终点锚点(^/$)
将与一行的起点/终点匹配。 -
s
ingle line (dotall): Dotall。Dot(.)
将匹配任何字符,包括换行符。 -
u
nicode: Unicode。 启用\x{FFFFF}
Unicode转义。 -
stick
y
: sticky。 该表达式只会从其lastIndex
位置进行匹配,并忽略全局(g)
标志(如果已设置)。
如果使用正则对象
在js中,使用正则对象主要有两种用法:
RegExp类
-
test:方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回
true
或false
参数:用来与正则表达式匹配的
字符串
返回值:如果正则表达式与指定的字符串匹配 ,返回true
;否则false
。
// 语法: regexObj.test(str)
const str = 'hello world!'
let result = /^hello/.test(str)
console.log(result) // true
注意⚠️ : 当设置全局标志的正则使用
test()
如果正则表达式设置了全局标志,
test()
的执行会改变正则表达式 lastIndex属性。连续的执行test()
方法,后续的执行将会从 lastIndex 处开始匹配字符串,exec()
同样改变正则本身的 lastIndex属性值)
- lastIndex: 是正则表达式的一个可读可写的整型属性,用来指定下一次匹配的起始索引。
const regex = /foo/g; console.log(regex.lastIndex) // 0 regex.test('foo') // true console.log(regex.lastIndex) // 3 regex.test('foo') // false
参数:要匹配正则表达式的
字符串
返回值:如果匹配成功,exec()
方法返回一个数组(包含额外的属性index
和input
,参见下方表格),并更新正则表达式对象的 lastIndex 属性。完全匹配成功的文本将作为返回数组的第一项,从第二项起,后续每项都对应正则表达式内捕获括号里匹配成功的文本。
// 语法: regexObj.exec(str)
// 匹配 "quick brown" 后跟 "jumps",忽略中间的字符
// 记住 "brown" 跟 "jumps"
// Ignore case 忽略大小写
const reg = /quick\s(brown).+?(jumps)/ig
let result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog')
// 结果:
// [
// 0: "Quick Brown Fox Jumps",
// 1: "Brown",
// 2: "Jumps",
// groups: undefined,
// index: 4,
// input: "The Quick Brown Fox Jumps Over The Lazy Dog",
// length: 3
// ]
下表列出这个脚本的返回值:
对象 | 属性/索引 | 描述 | 例子 |
---|---|---|---|
result |
[0] |
匹配的全部字符串 | Quick Brown Fox Jumps |
result |
[1],...[n] |
括号中的分组捕获 | [1] = Brownㅤㅤㅤㅤㅤㅤㅤ[2] = Jumps |
result |
index |
匹配到的字符位于原始字符串的基于0的索引值 | 4 |
result |
input |
原始字符串 | The Quick Brown Fox Jumps Over The Lazy Dog |
reg |
lastIndex |
下一次匹配开始的位置 | 25 |
reg |
ignoreCase |
是否使用了 "i " 标记使正则匹配忽略大小写 |
true |
reg |
global |
是否使用了 "g " 标记来进行全局的匹配. |
true |
reg |
multiline |
是否使用了 "m " 标记使正则工作在多行模式(也就是,^ 和 $ 可以匹配字符串中每一行的开始和结束(行是由 \n 或 \r 分割的),而不只是整个输入字符串的最开始和最末尾处。) |
false |
reg |
source |
正则匹配的字符串 | quick\s(brown).+?(jumps) |
String类
- search: 匹配符合匹配模式的字符串出现的位置。
参数:一个正则表达式对象。如果传入一个
非正则表达式
对象regexp
,则会使用new RegExp(regexp)
隐式地将其转换
为正则表达式对象。
返回值:如果匹配成功,则search()
返回正则表达式在字符串中首次匹配项的索引
;否则,返回-1
。
// 语法: str.search(regexp)
let str = "hey JudE";
const reg = /[A-Z]/g;
const reg1 = /[.]/g;
console.log(str.search(reg)) // 4, 这是第一个大写字母“J”的索引
console.log(str.search(reg1)) // -1 找不到 “.” 点标点
- match: 方法检索返回一个字符串匹配正则表达式的结果。
参数:一个
正则表达式
对象
- 如果传入一个非正则表达式对象,则会隐式地使用
new RegExp(obj)
将其转换为一个RegExp
。如果你没有给出任何参数并直接使用match() 方法 ,你将会得到一 个包含空字符串的Array
:[""]返回值:
- 如果
使用g
标志,则将返回与完整正则表达式匹配的所有结果,但不会返回捕获组。- 如果
未使用g
标志,则仅返回第一个完整匹配及其相关的捕获组(Array)。 在这种情况下,返回的项目将具有如下所述的其他属性。- 如果正则表达式不包含
g
标志,str.match()
将返回与 RegExp.exec() 相同的结果。
// 语法: str.match(regexp)
let str = 'For more information, see Chapter 3.4.5.1';
const reg = /see (chapter \d+(\.\d)*)/i;
let found = str.match(reg);
console.log(found);
// [
// 0: 'see Chapter 3.4.5.1',
// 1: 'Chapter 3.4.5.1',
// 2: '.1',
// groups: undefined,
// index: 22,
// input: 'For more information, see Chapter 3.4.5.1'
// ]
// 'see Chapter 3.4.5.1' 是整个匹配。
// 'Chapter 3.4.5.1' 被'(chapter \d+(\.\d)*)'捕获。
// '.1' 是被'(\.\d)'捕获的最后一个值。
// 'index' 属性(22) 是整个匹配从零开始的索引。
// 'input' 属性是被解析的原始字符串。
- replace: 使用指定的内容替换匹配模式的字符串。
参数:
- regexp (
pattern
):一个RegExp
对象或者其字面量。该正则所匹配的内容会被第二个参数
的返回值替换掉
。- substr (
pattern
):一个将被newSubStr
替换的字符串
。其被视为一整个字符串,而不是一个正则表达式。仅第一个匹配项会被替换。- newSubStr (
replacement
):用于替换掉第一个参数在原字符串中的匹配部分的字符串
。该字符串中可以内插一些特殊的变量名。- function (
replacement
): 一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。返回值:一个部分或全部匹配由替代模式所取代的新的字符串。
// 语法: str.replace(regexp|substr, newSubStr|function)
// newSubStr: 必需。一个字符串值。规定了替换文本或生成替换文本的函数。
// 下面是 特殊的变量名
// $1、$2、...、$99: 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本
// $$: 插入一个 '$'
// $&: 与 regexp 相匹配的子串
// $`: 位于匹配子串左侧的文本
// $': 位于匹配子串右侧的文本
// $$: 直接量符号
let str = 'aaa-bbb-ccc'
str.replace('aaa', 'ddd') // ddd-bbb-ccc
str.replace(/ddd/, 'aaa') // aaa-bbb-ccc
str.replace(/(aaa)-/, '$1~') // aaa~bbb-ccc
str.replace(/\a/g, (item, index, str) => {
console.log(item, index, str) // a 0 aaa-bbb-ccc
return index // 最后返回结果:"012-bbb-ccc"
})
-
split: 方法使用指定的分隔符字符串将一个
String
对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。
参数:
separator:指定表示每个拆分应发生的点的字符串。
separator
可以是一个字符串
或正则表达式
。 如果纯文本分隔符包含多个字符,则必须找到整个字符串来表示分割点。如果在str
中省略或不出现分隔符,则返回的数组包含一个由整个字符串组成的元素。如果分隔符为空字符串,则将str原字符串中每个字符的数组形式返回。limit:一个整数,限定返回的分割片段数量。当提供此参数时,
split
方法会在指定分隔符的每次出现时分割该字符串,但在限制条目已放入数组时停止。如果在达到指定限制之前达到字符串的末尾,它可能仍然包含少于限制的条目。新数组中不返回剩下的文本。返回值:返回源字符串以分隔符出现位置分隔而成的一个
Array
// 例子1: separator 是字符串
let myString1 = 'Hello World. How are you doing?'
console.log(myString1.split(' '))
// ["Hello", "World.", "How", "are", "you", "doing?"]
console.log(myString1.split(' ', 3))
// ["Hello", "World.", "How"]
// 例子2: separator 是正则
let myString2 = 'Hello 1 word. Sentence number 2.'
let splits = myString2.split(/(\d)/)
console.log(myString2.split(/\d/))
// ["Hello ", " word. Sentence number ", "."]
console.log(myString2.split(/(\d)/))
// ["Hello ", "1", " word. Sentence number ", "2", "."] 如果正则中有子表达式,那么配置的 子表达式 也会被匹配进去
子表达式()
let str = '12312312php2545fxx'
// 例如:/(\d)php/中的"(\d)"就是一个子表达式
捕获
在正则匹配模式中,子表达式匹配到的内容会被系统捕获至系统的缓冲区中,我们称之为捕获
var str = '12312312php2545fxx'
// 例如:/(\d)php/ //2php 2就被捕获至系统 **1号** 的缓冲区中
反向引用
捕获之后,可以在匹配模式中使用\n(n:数字)来引用系统的第n号缓冲区内容
let str = '12312312php2545fxx'
// 例如:/(\d)php\1/ //匹配的就是2php2了,\1是引用了1号缓冲区中的2,因为php前面的是2
- 例子
// + 匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}
// * 匹配前面的子表达式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等价于{0,}。
// \w 匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集
// \W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”
// . 匹配除“\n”和"\r"之外的任何单个字符。要匹配包括“\n”和"\r"在内的任何字符,请使用像“[\s\S]”的模式。
let str1 = 'qewqsjava111javadssphp222php9uiyu33owds'
const reg1 = /(\W+)\d\d\d\1/gi;
str.match(reg1)
// 结果java111java, php222php
const reg2 = /(\w+)\d\d\d\1/gi;
let result;
while (result=reg2.exec(str)) {
alert(result)
}
// result[0]:java111java 这是匹配到的内容
// result[1]:java 这里是第一个子表达式的值
// result[0]:php222php
// result[1]:php
// 查找连续相同的四个数字,如:1208
const reg = /\d\d\d\d/gi //或者var reg = /\d{3}/gi
// 查找连续相同的四个数字,如:1111
const reg = /\d\1\1\1/gi
// 查找数字,如:1221,3443
const reg = /(\d)(\d)\2\1/gi //1111这样的也会匹配到
// 查找字符,如:AABB,TTMM
const reg = /(\w)\1(\w)\2/gi
// 查找连续相同的四个数字或四个字符
const reg = /(\w)\1\1\1/gi
// 再一个字符串,查找一对html标记以及中间的内容
let str2 = iqeos<div>标签</div>adasdda<p>100.00p</p>qewq
const reg = /<(\w+)>.*<\/\1>/gi
一般情况下,后面的内容要求与前面的一致,就会用的子表达式、捕获、反向引用
-
exec方法和match方法的比较:
exec
方法是RegExp
类下的方法
match
是String
下的方法
match
方法直接返回一个数组
exec
方法需要循环反复调用
如果有子表达式,exec
方法将子表达式的捕获结果放到数字对应的元素中
正则语法
正则表达式是由普通字符(例如字符 a-z ,0-9)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
普通字符:a-z,0-9 等等
特殊字符(元字符):\d \s \w . * 等等
-
(1)限定符
限定符可以指定正则表达式的一个给定组件必须要出现多少次才能满足匹配
* 匹配前面的组件零次或者多次
+ 匹配前面的组件一次或者多次
? 匹配前面的组件零次或者一次
{n} 匹配确定的 n 次
{n,} 至少匹配 n 次
{n,m} 最少匹配 n 次且最低匹配 m 次
-
* , + , ? 也可以用下面的方式表示
-
*
{0,} -
+
{1,} -
?
{0,1}
-
-
(2)字符匹配符
-
字符匹配符用于匹配某个或某些字符
带有[]的叫字符簇,一个簇表示一个字符
[a-z]
:表示 a-z 任意一个字符
[A-Z]
:表示 A-Z 任意一个字符
[0-9]
:表示0-9任意一个字符
[0-9a-z]
:表示 0-9 a-z 任意一个字符
[0-9a-zA-Z]
:表示 0-9 a-z A-Z任意一个字符
[abcd]
:表示a或b或c或d 任意一个字符
[1234]
:表示1或2或3或4 任意一个字符
[^a-z]
:表示除了 a-z 以外的任意字符
[^0-9]
:表示除了0-9以外的任意字符
[^abcd]
:表示除了1或2或3或4 以外的任意字符
\d
:匹配一个数字字符[0-9]
\D
:匹配一个非数字字符[^0-9]
\w
:匹配包括下划线的任意单词字符[0-9a-zA-Z_]
\W
:匹配任何非单词字符[^0-9a-zA-Z_]
\s
:匹配任何空白字符 (空格、制表符、换行符)
\S
:匹配任何非空白字符
.
:匹配除 “\n” 之外的任何单个字符
-
-
(3)定位符
定位符可以将一个正则表达式固定在一行的开始或者结束。也可以创建只在单词内或只在单词的开始或者结尾处出现的正则表达式
^
:匹配字符串的开始位置
$
:匹配字符串的结束位置
\b
:匹配单词的开始位置或结束位置
\B
:匹配不是单词开头位置或结束位置
注意:在字符簇的^跟不表达式里^是不同意思的
- 例如
[^x]
:匹配除了x以外的任意字符
[^aeiou]
:匹配除了aeiou这几个字母以外的任意字符const reg = /^a/ //表示匹配第一个位置a const reg1 = /\Ba\B/ //表示匹配前后都不是单词边界的a
- 例子:验证年龄
const reg = /^/d/d $/g
- 例如
(4)转义符
\
:用于匹配某些特殊字符-
(5)选择匹配符
|
:可以匹配多个规则- 例子:
const str = 'hello Java,hello JavaScript' const reg = /hello (JavaScript|Java)/g console.log(str.match(reg)) // ["hello Java", "hello JavaScript"]
(6)关于正则表达式的几种特殊用法
名称 | 正则 | 描述 |
---|---|---|
(?:x) 非捕获组(Non-capturing group ) |
/(?:\d)/.exec('2019') |
使用了() 捕获,不会出现在捕获中 |
(?=) 正向前瞻 (Negative lookahead ) 也叫先行断言
|
x(?=y) |
匹配x 仅仅当x 后面跟着y 这种叫做 先行断言
|
x(?!y) ****(Positive lookahead ) |
(?=)
正向前瞻:
let str = 'xxx好人,xxx好好人'
const reg = /xxx(?=好人)/gi
console.log(str.match(reg)) // ["xxx"](xxx好人的xxx)
- 例如:
\d{3,5}
//匹配最少3个最多5个的数子
const str = 'jau123123122wjqei78781h123ui131213aa'
const reg = /\d{3,5}/gi
console.log(str.match(reg))
// 结果:["12312", "3122", "78781", "123", "13121"]
上面这个例子中,既匹配三个,也可以匹配五个,那么,正则表达式中会自动匹配最多的那一种,这在正则中叫贪婪匹配原则
在表达式的后面使用" ? ",表示非贪婪匹配原则,但是不会去匹配4个数字或者5个数字了
- 例如
const str = '123456q1234e12345'
const reg = /\d{3,5}?/gi
console.log(str.match(reg))
//结果: ["123", "456", "123", "123"]
- 例子:替换重复的字
let str = '我..是是.是.一一个个..好好.好人.人人'
let reg = /\.+/g
str = str.replace(reg,'') // "我是是是一一个个好好好人人人"
reg = /(.)\1+/g
str = str.replace(reg,'$1') // "我是一个好人"
// $1是1号缓冲区内容替换重复的内容
- 例子:验证ip是否有效
// 规则
// 例子 1.1.1.1
// 0-255
// 第一个段不能是0
// 不能以0开头 如:011
const ip = '192.168.0.32'
const reg = /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/g
if (reg.test(ip)) {
console.log('合法')
} else{
console.log('不合法')
}
- 例子:验证邮箱是否有效
const email = '347904341@cctv.admin.pl'
const reg = /^[\w\.]+@(\w+\.)+[a-z]{2,5}$/gi
if (reg.test(email)) {
console.log('合法')
} else{
console.log('不合法')
}
- 例子: 密码强度校验,密码6-20位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
const reg = /^(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[.!@#$%^&? ])\S{6,20}$/
reg.test('123Aa!') // true
reg.test('45678901234567890Aa!') // true
reg.test('456789012345678901Aa!') // false