匹配
刀刀
0字
0分钟
2026/8/16
重复匹配
重复匹配基本使用
如果要重复匹配一些内容时我们要使用重复匹配修饰符,包括以下几种。
| 符号 | 说明 |
|---|---|
| * | 重复零次或更多次 |
| + | 重复一次或更多次 |
| ? | 重复零次或一次 |
| {n} | 重复 n 次 |
| {n,} | 重复 n 次或更多次 |
| {n,m} | 重复 n 到 m 次 |
因为正则最小单位是元字符,而我们很少只匹配一个元字符如 a、b 所以基本上重复匹配在每条正则语句中都是必用到的内容。
默认情况下重复选项对单个字符进行重复匹配,即不是贪婪匹配
js
let fn = 'fnddd'
console.log(fn.match(/fnd+/i)) //fnddd使用原子组后则对整个组重复匹配
js
let fn = 'fnddd'
console.log(fn.match(/(fn)+/i)) //fn下面是验证坐机号的正则
js
let fn = '010-12345678'
console.log(/0\d{2,3}-\d{7,8}/.exec(fn))验证用户名只能为 3~8 位的字母或数字,并以字母开始
html
<body>
<input type="text" name="username" />
</body>
<script>
let input = document.querySelector(`[name="username"]`)
input.addEventListener('keyup', (e) => {
const value = e.target.value
let state = /^[a-z][\w]{2,7}$/i.test(value)
console.log(
state ? '正确!' : '用户名只能为3~8位的字母或数字,并以字母开始',
)
})
</script>验证密码必须包含大写字母并在 5~10 位之间
html
<body>
<input type="text" name="password" />
</body>
<script>
let input = document.querySelector(`[name="password"]`)
input.addEventListener('keyup', (e) => {
const value = e.target.value.trim()
const regs = [/^[a-zA-Z0-9]{5,10}$/, /[A-Z]/]
let state = regs.every((v) => v.test(value))
console.log(state ? '正确!' : '密码必须包含大写字母并在5~10位之间')
})
</script>重复匹配禁止贪婪
正则表达式在进行重复匹配时,默认是贪婪匹配模式,也就是说会尽量匹配更多内容,但是有的时候我们并不希望他匹配更多内容,这时可以通过?进行修饰来禁止重复匹配
| 使用 | 说明 |
|---|---|
| *? | 重复任意次,但尽可能少重复 |
| +? | 重复 1 次或更多次,但尽可能少重复 |
| ?? | 重复 0 次或 1 次,但尽可能少重复 |
| {n,m}? | 重复 n 到 m 次,但尽可能少重复 |
| {n,}? | 重复 n 次以上,但尽可能少重复 |
下面是禁止贪婪的语法例子
js
let str = 'aaa'
console.log(str.match(/a+/)) //aaa
console.log(str.match(/a+?/)) //a
console.log(str.match(/a{2,3}?/)) //aa
console.log(str.match(/a{2,}?/)) //aa将所有 span 更换为 h4 并描红,并在内容前加上 刀刀-
html
<body>
<main>
<span>houdunwang</span>
<span>fndd.com</span>
<span>daodao.com</span>
</main>
</body>
<script>
const main = document.querySelector('main')
const reg = /<span>([\s\S]+?)<\/span>/gi
main.innerHTML = main.innerHTML.replace(reg, (v, p1) => {
console.log(p1)
return `<h4 style="color:red">刀刀-${p1}</h4>`
})
</script>下面是使用禁止贪婪查找页面中的标题元素
html
<body>
<h1>daodao.com</h1>
<h2>fndd.com</h2>
<h3></h3>
<h1></h1>
</body>
<script>
let body = document.body.innerHTML
let reg = /<(h[1-6])>[\s\S]*?<\/\1>/gi
console.table(body.match(reg))
</script>全局匹配
全局匹配问题分析
下面是使用 match 全局获取页面中标签内容,但并不会返回匹配细节
html
<body>
<h1>daodao.com</h1>
<h2>fndd.com</h2>
<h1>刀刀</h1>
</body>
<script>
function elem(tag) {
const reg = new RegExp('<(' + tag + ')>.+?<\.\\1>', 'g')
return document.body.innerHTML.match(reg)
}
console.table(elem('h1'))
</script>全局匹配matchAll
在新浏览器中支持使用 matchAll 操作,并返回迭代对象
需要添加
g修饰符
js
let str = 'daodao'
let reg = /[a-z]/gi
for (const iterator of str.matchAll(reg)) {
console.log(iterator)
}在原型定义 matchAll 方法,用于在旧浏览器中工作,不需要添加 g 模式运行
js
String.prototype.matchAll = function (reg) {
let res = this.match(reg)
if (res) {
let str = this.replace(res[0], '^'.repeat(res[0].length))
let match = str.matchAll(reg) || []
return [res, ...match]
}
}
let str = 'daodao'
console.dir(str.matchAll(/(o)/i))全局匹配exec
使用 g 模式修正符并结合 exec 循环操作可以获取结果和匹配细节。注意:如果不添加 g 全局匹配,会造成死循环。因为代码 /u/i.exec('daoudaou') 会一直匹配第三项,不会往下匹配了。
html
<body>
<h1>daodao.com</h1>
<h2>fndd.com</h2>
<h1>刀刀</h1>
</body>
<script>
function search(string, reg) {
const matchs = []
while ((data = reg.exec(string))) {
matchs.push(data)
}
return matchs
}
console.log(search(document.body.innerHTML, /<(h[1-6])>[\s\S]+?<\/\1>/gi))
</script>使用上面定义的函数来检索字符串中的网址
js
let fn = `https://fndd.com
https://www.sina.com.cn
https://www.daodao.com`
let res = search(fn, /https?:\/\/(\w+\.)?(\w+\.)+(com|cn)/gi)
console.dir(res)