Skip to content

2-18正则表达式和元字符(二) ​

本页对应 第二章WebAPIs,共 4 段视频,约 29 分钟。

学习目标 ​

  • 能列举并解释字符类元字符 \d、\D、\w、\W、\s、\S 的匹配含义,并能说明大小写形式互为相反匹配。
  • 能使用字符类和量词读懂并改写日期格式正则,说明年、月、日各分组及分隔符的匹配规则。
  • 能使用 replace() 完成字符串替换,说明两个参数的作用、返回值为替换后的新字符串且不修改原字符串。
  • 能使用修饰符 i 和 g 控制正则匹配细节,并实现忽略大小写替换与全局替换。
  • 能编写隐藏手机号中间四位的案例,使用分组捕获 $1、$2、repeat() 和模板字符串实现手机号脱敏及仅显示后四位的变体。
  • 能安装并使用 VS Code 插件 any-rule,通过“正则大全”按关键字检索并插入手机号、QQ 号等正则;能结合 change 事件在表单值改变时触发正则校验或替换。

知识点 ​

为什么需要 any-rule 这类正则插件 ​

正则插件 any-rule 使用示意

为什么需要: 正则学到后面会发现,很多表达式“看懂不难,默写很难”。转写稿里也明确说:正则“没学过是真看不懂,学过了也不一定能写得出来、背得过”,大多数场景是拿现成规则来改、来用。
怎么想: 不要把插件当成“代替学习”的工具,而是当成“查表工具”。字符类、替换、修饰符这些基础仍要懂,否则插件生成的正则复制过来也不会改。
怎么做: 在 VS Code 扩展商店搜索 any-rule,安装后右键选择“正则大全”,再按关键字搜索,例如“手机号”,会看到严谨、宽松等不同版本,点选后即可插入到代码里。
易错点: 插件生成的是“正则文本”,复制后要检查锚点、转义和标志位;表单验证常用 test,字符串替换常用 replace,两者不能混着用。

怎么想:先会改,再会写 ​

为什么需要: 转写稿里反复强调,学正则不是为了手动背长表达式,而是为了验证表单、做替换等操作。
怎么想: 拿到插件生成的正则后,先看它匹配什么:是数字、字母数字下划线,还是手机号;再看有没有 ^、$、括号捕获组和 g、i 修饰符。
怎么做: 例如手机号隐藏案例中,先用正则把手机号划分成“前三位、中间四位、后四位”,再用 replace 替换中间四位。核心代码如下:

js
const phone = '13611112222'
const reg = /^(\d{3})\d{4}(\d{4})$/
const result = phone.replace(reg, '$1****$2')
console.log(result) // 136****2222

这里 \d 是字符类,表示 0 到 9 的任意数字;(\d{3}) 和 (\d{4}) 是捕获组,替换字符串里的 $1、$2 分别取第一个、第二个小括号里的内容。
易错点: replace 默认只替换第一个匹配项,要全部替换需加 g;字符串本身不会被修改,replace 返回替换后的新字符串。转写稿中第一次只替换了一个“前端”,就是因为没有加 g。

怎么做:安装插件并插入正则 ​

为什么需要: 手机号、QQ 号、网址、银行卡等规则写起来长,插件能减少查找和手写成本。
怎么想: 先明确业务要“严谨”还是“宽松”。转写稿演示了手机号有严谨、宽松、最宽松等选项,选错会导致该通过的校验不通过,或不该通过的却通过。
怎么做: 在 VS Code 中右键,选择“正则大全”,输入关键字,例如“手机号”,点击需要的条目,正则就会插入光标处。视频里还演示了 QQ 号、网址等条目。
易错点: 不要直接背插件里的长正则;插入后要按业务补 ^、$ 做整串校验,替换场景再考虑是否加 g。

用插件生成的正则做手机号隐藏调试 ​

为什么需要: 只显示后四位也是常见需求,例如打车场景。
怎么想: 可以把后四位放进捕获组,前面七位用星星替换;也可以先写七个星星,再拼 $1。
怎么做:

js
const phone = '13611112222'
const result2 = phone.replace(/^\d{7}(\d{4})$/, '*******$1')
console.log(result2) // *******2222

const stars = '*'.repeat(7)
const result3 = phone.replace(/^\d{7}(\d{4})$/, `${stars}$1`)
console.log(result3) // *******2222

repeat 是字符串方法,不是正则量词;模板字符串里调用方法要写成 \${stars}。
易错点: 捕获组编号要和括号顺序对应;$1 写在普通字符串和模板字符串里都表示替换引用,但模板字符串中的 \${...} 会先执行 JavaScript 表达式。调试时先 console.log 看替换结果,再写入页面,例如 document.querySelector('.phone').innerHTML = result。

先说明:本节转写稿与 change 事件不匹配 ​

本节笔记只有一句核心内容:给 input 注册 change 事件,值被修改并且失去焦点后触发。但提供的转写稿讲的是正则字符类、replace 替换、修饰符、隐藏手机号中间四位以及 any-rule 插件,和“change 事件”不是同一主题。因此下面不把正则内容硬塞进 change 事件教程,只依据本节笔记扩写;转写稿中“原字符”应为“元字符”、“政则”应为“正则”等同音转写问题,也与本节无关,不展开。

change 事件到底解决什么问题 ​

为什么需要:文本框如果注册 input 事件,用户每输入一个字符就会触发一次。做实时搜索、字数统计时这很有用;但做“输入完成后确认”“失焦后校验”“选择后联动”时,频繁触发反而不合适。change 的价值在于:它不追踪每一次按键,而是在值被修改并且失去焦点后给出一次确认。

怎么想:把 change 理解成“用户对这次输入做了一个阶段性提交”。对文本输入框来说,用户还在输入时不算提交;当用户点击页面空白、切换到下一个控件,也就是失去焦点后,浏览器才检查值是否变化,变化了才触发 change。

怎么做:先获取 input,再用 addEventListener('change', handler) 注册。事件处理函数里通过 e.target.value 或 input.value 读取当前值。

易错点:不要用 change 做逐字实时校验;不要以为只要失焦就触发,值没变不会触发;不要混淆 onchange 属性写法和 addEventListener 写法。

用代码观察 change 的触发时机 ​

为什么需要:只看定义容易把 change、input、blur 混在一起。用控制台日志观察触发顺序,能直观看到“输入中”和“失焦后”的差别。

怎么想:同一个 input 同时注册 input、change、blur 三个事件。输入文字时观察 input 是否连续触发;点击空白失焦时观察 change 是否出现;不改值直接失焦时观察 change 是否出现。

怎么做:

js
<label>
  用户名:
  <input id="username" type="text" value="小明">
</label>
<p id="tip"></p>

<script>
  const input = document.querySelector('#username');
  const tip = document.querySelector('#tip');

  input.addEventListener('input', function () {
    console.log('input 触发,当前值:', input.value);
  });

  input.addEventListener('change', function (e) {
    console.log('change 触发,当前值:', e.target.value);
    tip.textContent = `已确认的值:${e.target.value}`;
  });

  input.addEventListener('blur', function () {
    console.log('blur 触发');
  });
</script>

调试时打开控制台:在输入框里连续输入,会看到多次 input;点击页面空白后,如果值确实变了,会看到 change;如果什么都没改就失焦,通常不会看到 change。不要依赖 change 与 blur 的先后顺序去写复杂业务逻辑,业务判断应放在 change 处理函数内部完成。

易错点:用 JavaScript 直接写 input.value = '新值' 不会自动触发 change,它只改变值,不模拟用户操作;如果确实需要,要手动派发事件。另一个易错点是读取值时写错对象,应该用 e.target.value 或已获取的 input 元素。

不同表单控件的 change 表现 ​

为什么需要:change 不只用于文本框。复选框、单选框、下拉框也会触发,但触发时机和文本框不完全一样。

怎么想:文本输入框需要“值改变 + 失去焦点”;复选框、单选框、下拉框更接近“用户完成一次选择”就触发。写代码前先确认控件类型,不要把所有控件都套成“失焦才触发”。

怎么做:给 select 注册 change,选择不同选项后读取 select.value;给 checkbox 注册 change,切换后读取 checkbox.checked。例如:

html
<select id="city">
  <option value="bj">北京</option>
  <option value="sh">上海</option>
</select>

<script>
  const city = document.querySelector('#city');
  city.addEventListener('change', function (e) {
    console.log('选择的城市:', e.target.value);
  });
</script>

易错点:不要用文本框的“失焦”经验解释所有控件的 change;不要忘记 select 读取的是 value,checkbox 读取的是 checked;不要在事件外反复查询 DOM,能缓存元素就缓存。

什么时候该用 change,什么时候不该用 ​

为什么需要:事件选错会导致体验变差。实时搜索用 change 会显得“慢半拍”;而最终确认、失焦校验、下拉联动用 input 又可能触发过频。

怎么想:需要“每次输入都响应”就用 input;需要“用户完成输入后再确认”就用 change;需要“只要失焦就做事”才用 blur。三者目的不同,不要互相替代。

怎么做:表单校验可以监听 change,在用户离开输入框后给出提示;实时联想、字数统计监听 input;纯 UI 失焦效果监听 blur。

易错点:把 change 当成“值一变就触发”是常见误解;值改回原值后是否触发,受浏览器对“值是否改变”的判断影响,实际开发中应以目标浏览器测试为准,不要写依赖这种边界行为的核心逻辑。

课件图示 ​

课件第35页:步骤 小兔鲜页面注册 业务②: 表单验证业务 1. 用户名验证(注意封装函数 v

课件第28页:可以帮我们快速生成正则表达式 any-rule 推荐一个vscode正则插件

课件第5页:1.1.1 什么是正则表达式 l 正则表达式(Regular Expressio

课件第6页:1.1.2 正则基本使用 l 正则基本使用分为两步: 定义规则 使用正则 l c

课件第7页:总结 总结 1.正则表达式是什么? Ø 是一种字符串匹配的模式(规则) 2.正则

课件第20页:案例 用户名验证案例 需求:用户名要求用户英文字母,数字,下划线或者短横线组成,

课件第26页:1.3 替换和修饰符 l 修饰符约束正则执行的某些细节行为,如是否区分大小写、是

课件第27页:案例 利用正则隐藏手机号中间四位 分析: ①:手机号前三位显示,中间四位隐藏为*

代码示例 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>replace 替换与修饰符</title>
</head>
<body>
  <script>
    const str = '欢迎大家来学前端,谢谢大家一定能学好前端,都成为前端大神'

    // 1. 没有修饰符:只替换第一个
    const str1 = str.replace(/前端/, 'web')
    console.log(str1) // 只有第一个"前端"变成了 web

    // 2. g 修饰符(global 全局):全部替换
    const str2 = str.replace(/前端/g, 'web')
    console.log(str2) // 三个"前端"全部变成 web

    // 3. 把关键字替换成星星,实现隐藏
    console.log(str.replace(/前端/g, '**'))

    // 4. i 修饰符(ignore 忽略):忽略大小写
    console.log(/a/.test('a'))    // true
    console.log(/A/.test('a'))    // false
    console.log(/A/i.test('a'))   // true

    // 5. g 和 i 可以一起用
    console.log('A a A'.replace(/a/gi, 'x'))
  </script>
</body>
</html>

要点解释与易错点

  • replace(规则, 替换成什么) 有两个参数,第一个参数可以是正则表达式,第二个参数是替换后的内容。
  • replace 不会修改原字符串,而是返回一个替换完成后的新字符串,所以要拿变量接住返回值。
  • 不加 g 只替换第一个匹配项,这是最容易出错的地方;需要全部替换必须在正则最后加 g。
  • i 是 ignore 的缩写,加在正则最后的斜杠后面,表示不区分大小写;g 是 global,表示全局匹配。
  • 修饰符写在正则的最后一个斜杠之后:/前端/g,不要写成 /g前端/。

js
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>隐藏手机号中间四位</title>
</head>
<body>
  <div class="phone"></div>

  <script>
    const tel = '13611112222'

    // 需求一:隐藏中间四位,保留前三位和后四位
    // 正则把手机号划分成三段:(\d{3}) 前三位  \d{4} 中间四位  (\d{4}) 后四位
    const reg = /^(\d{3})\d{4}(\d{4})$/
    const str = tel.replace(reg, '$1****$2')
    console.log(str) // 136****2222

    document.querySelector('.phone').innerHTML = `恭喜 ${str} 的小伙伴得到了我们的奖品`

    // 需求二:只显示后四位,前七位用星星隐藏
    const reg2 = /^\d{7}(\d{4})$/
    console.log(tel.replace(reg2, '*******$1'))

    // 需求二升级:星星太多不想一个个写,用 repeat 重复字符串
    console.log('*'.repeat(7))                 // *******
    console.log('开心'.repeat(8))              // 开心开心...
    console.log(tel.replace(reg2, `${'*'.repeat(7)}$1`))
  </script>
</body>
</html>

要点解释与易错点

  • \d 是字符类,等价于 [0-9],表示 0-9 之间的任意一个数字;\D 则相反,表示"不是数字"。大小写含义正好相反,不要写混。
  • {3}、{7} 是量词,表示前面那个字符重复的次数;{1,2} 表示重复 1 到 2 次。
  • 正则两端一定要加 ^ 和 $,否则只匹配到一部分也会替换,结果就会乱。
  • $1 拿到的是第一个小括号里的内容,$2 拿到第二个小括号里的内容,顺序按左括号出现的先后算。没加小括号的部分(中间四位)不会被 $n 取到。
  • repeat() 是字符串的方法,不是正则的,'*'.repeat(7) 返回 7 个星号;正则里重复用的是量词。
  • 模板字符串里调用方法要写成 \${'*'.repeat(7)},不能直接写在单引号字符串里。
  • 别忘 replace 有返回值,要接住或者直接写进 innerHTML。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>change 事件 + 正则校验</title>
  <style>
    input { padding: 6px; outline: none; }
    .ok { border: 2px solid green; }
    .err { border: 2px solid red; }
  </style>
</head>
<body>
  <input type="text" id="phone" placeholder="请输入手机号">

  <script>
    const input = document.querySelector('#phone')

    // change:值被修改并且失去焦点后触发
    input.addEventListener('change', function () {
      // 手机号:11 位纯数字
      const reg = /^\d{11}$/
      this.className = reg.test(this.value) ? 'ok' : 'err'
    })
  </script>
</body>
</html>

要点解释与易错点

  • change 事件的触发条件是"值被修改并且失去焦点",只输入不离开输入框是不会触发的,这一点和 input 事件不同。
  • 校验用 reg.test(值),返回布尔值,比 exec 更适合做表单判断。
  • 正则里 ^ 表示开头、$ 表示结尾,漏掉就会出现"包含 11 位数字就算通过"的错误结果。
  • 复杂正则不必手写,可以装 VS Code 的 any-rule 插件,右键选"正则大全",搜"手机号"等关键字直接取用;重点是学会拿正则去做验证。

常见错误 ​

1. 替换只生效一次,后面的同名内容原样保留

  • 现象:str.replace(/前端/, 'web') 执行后,只有第一处“前端”被替换。
  • 原因:正则默认非全局匹配,replace 只处理第一个命中项。
  • 修法:给正则加 g 修饰符 —— str.replace(/前端/g, 'web');若要同时忽略大小写,写成 /前端/gi。

2. 以为 replace 会改动原字符串,结果打印出来没变化

  • 现象:str.replace(...) 之后 console.log(str) 仍是旧内容。
  • 原因:字符串不可变,replace 是返回一个新字符串,不修改调用者。
  • 修法:接住返回值 —— const newStr = str.replace(...),或 str = str.replace(...)。

3. 用 $1 拼接却拿到字面量 $1

  • 现象:替换结果里直接出现 $1 文本,而不是分组内容。
  • 原因:正则里对应的部分没有用小括号分组,或者 $1 写在了正则里而非替换字符串里;分组序号也数错了($1 是第一个左括号,按左括号出现顺序编号)。
  • 修法:先用小括号把要保留的片段括起来,再在第二个参数里按顺序引用 $1、$2;可用 str.match(reg) 先确认分组结果。

4. 模板字符串里写 repeat 没加 ${},输出一坨字面量

  • 现象:页面上显示 '*'.repeat(7)$1 这样的原文。
  • 原因:反引号里不加 ${} 的部分都是纯文本,方法调用不会执行。
  • 修法:写成 `\${'*'.repeat(7)}$1`,注意 repeat 是字符串的方法,repeat(7) 表示重复 7 次。

5. 手机号正则不加首尾锚点,替换位置错乱

  • 现象:号码位数不对时(如 10 位、12 位)依然被“成功”隐藏,或前几位被吃掉。
  • 原因:没写 ^ 和 $,正则从任意位置开始匹配;分组数量与实际位数不匹配。
  • 修法:写成 /^(\d{3})\d{4}(\d{4})$/,用 ^...$ 锁定整串,并保证 3 + 4 + 4 = 11 位。

6. 用 change 做实时校验,输入过程中毫无反应

  • 现象:边打字边看不到提示,必须点别处才触发。
  • 原因:change 的触发条件是“值被修改且失去焦点”,输入过程中不会触发。
  • 修法:需要实时反馈改用 input 事件;确实要等用户填完再校验(如手机号、邮箱)就用 change 或 blur。

练习 ​

1. 全局替换 + 忽略大小写 把 "JavaScript 很好玩,我喜欢 javascript,JAVASCRIPT 最强" 中所有大小写形式的 javascript 替换为 JS,并打印结果与原字符串对比,说明哪个变了。

2. 字符类判断 用 \w、\d、\s 写三个正则,分别判断以下字符串是否“只由字母数字下划线组成”“只由数字组成”“包含空白字符”: "abc_123"、"abc-123"、"123456"、"hello world"。

3. 手机号脱敏(两个需求) 给定 const tel = '13812345678':

  • 需求 A:隐藏中间四位 → 138****5678,用分组 + $1 $2 实现;
  • 需求 B:只显示后四位 → *******5678,分别用「手写 7 个星号」和「repeat + 模板字符串」两种写法实现。

4. 表单联动 页面上放一个输入框和一个展示区:用户输入手机号后失去焦点(change),若格式合法(用 ^\d{11}$ 或 any-rule 插件生成的正则校验),就在展示区输出脱敏后的号码;不合法则提示“请输入 11 位手机号”。

5. 插件实战 安装 any-rule 插件,右键 → 正则大全,分别取一个「手机号(宽松)」和「QQ 号」的正则,套进 test() 里验证 3 组正确数据和 3 组错误数据,记录哪条规则最符合你的业务需要。

原视频对照 ​

#视频时长
1元字符之字符类05:27
2替换和修饰符07:39
3隐藏手机号中间四位的案例13:22
4推荐一个正则插件any-rule03:26

小结 ​

  1. 字符类是“常见模式的简写”:\d/\D、\w/\W、\s/\S,小写是“是”,大写是“不是”,每组都只匹配一个字符。
  2. 字符类让日期、手机号这类正则从“看不懂”变成“能读懂”,2099-1-1 这种写法靠 \d{4}、\d{1,2} 就能解释清楚。
  3. replace(规则, 替换内容) 两个参数缺一不可,规则可以是字符串也可以是正则;它返回新字符串,不改原串。
  4. 修饰符写在正则最后一条斜杠之后:i 忽略大小写,g 全局匹配——replace 只替换一处,九成是因为漏了 g。
  5. 小括号是“分组捕获”,$1、$2 按左括号顺序取值;脱敏案例就是靠“保留分组 + 中间塞星号”完成的。
  6. repeat(n) 是字符串方法,用来重复字符串;在模板字符串中必须用 ${} 包裹才会执行。
  7. change 是“改完并失焦”才触发,实时校验请换 input;两者选哪个取决于业务要不要即时反馈。
  8. 正则不必背,会改、会验证表单就够用;any-rule 这类插件能直接生成常用正则,把精力放在“用对地方”上。