跳转到内容

匹配

刀刀
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)

贡献者

The avatar of contributor named as duyidao duyidao
The avatar of contributor named as v_duyilin v_duyilin
The avatar of contributor named as 刀刀 刀刀

页面历史

刀刀博客累计访客 人;文档累计访问量共