讲解

字符类用一对方括号表示「这个位置可以是方括号里列出的任意一个字符」:[aeiou] 匹配任意一个英文元音字母。方括号里可以用连字符写范围:[a-z] 是小写字母,[0-9] 是数字,[a-zA-Z0-9] 把几段拼在一起表示字母或数字。注意字符类匹配的永远是「一个字符」,[0-9] 匹配一位数字而不是一个数。

方括号内第一个字符是 ^ 时表示取反:[^0-9] 匹配「任意一个非数字字符」。取反很容易用错——[^0-9] 要求那个位置必须存在一个字符且不是数字,它不能表达「这里没有数字」。另外记住一个便利规则:字符类内部大多数字符是字面量,[.] 匹配点号、[+] 匹配加号,不需要转义。

正则还内置了几个高频字符类的缩写:\d 等价 [0-9](数字),\w 等价 [a-zA-Z0-9_](单词字符,注意包含下划线),\s 匹配空白(空格、制表符、换行等)。它们各自的大写版本是取反:\D 非数字、\W 非单词字符、\S 非空白。要特别小心 \w 的边界:它既不包含汉字,也不包含连字符,和直觉里的「单词」并不完全等同。匹配汉字通常用 Unicode 范围 [\u4e00-\u9fa5],其中 \u4e00 和 \u9fa5 分别是常用汉字区间的两端。

示例

// 方括号:枚举或范围,匹配其中一个字符
console.assert(/[aeiou]/.test('hello')); // 含有元音字母
console.assert(/^[0-9]{4}$/.test('2026')); // 四位数字
console.assert(/^[a-z][a-z0-9-]{2,}$/.test('ohmy-docs')); // 小写字母开头的 slug
console.assert(/^[a-z][a-z0-9-]{2,}$/.test('1bad') === false);

// ^ 在方括号内表示取反
console.assert(/[^0-9]/.test('a1')); // 存在非数字字符
console.assert(/^[^0-9]+$/.test('abc')); // 整串不含数字
console.assert(/^[^0-9]+$/.test('a1') === false);

// 字符类内部的点号是字面量,不用转义
console.assert(/\d[.]\d/.test('3.14'));
console.assert(/\d[.]\d/.test('3a4') === false);

预定义字符类 \d \w \s 及其大写取反版本:

console.assert(/\d\d-\d\d/.test('08-09'));
console.assert(/^\w+$/.test('abc_123')); // \w = 字母、数字、下划线
console.assert(/^\w+$/.test('中文') === false); // 默认不含汉字
console.assert(/^\w+$/.test('a-b') === false); // 也不含连字符
console.assert(/\s/.test('a b')); // 空白字符
console.assert(/^\S+$/.test('no-space')); // 整串无空白

// 匹配汉字:Unicode 范围(一 到 龥 覆盖常用汉字)
console.assert(/^[一-龥]+$/.test('正则表达式'));
console.assert(/^[一-龥]+$/.test('正则abc') === false);

常见坑

  • 以为 [a-z] 包含大写字母:不包含。[a-zA-Z] 才是任意字母,或者加 i 标志。
  • 以为 \w 能匹配「单词」里的一切:\w 不含汉字、不含连字符、不含点号。校验用户名「能否包含中文」时先想清楚需求,别顺手写 \w+。
  • 取反符号位置写错:^ 只有紧跟在 [ 后面才是取反,[a^b] 里的 ^ 就是字面字符;写在方括号外则是行首锚点。
  • 范围端点写反:[z-a] 会直接抛语法错误。范围必须按编码从小到大,写 [a-z] 而不是 [z-a]。

小结

字符类 [ ] 匹配列出的任一字符,支持范围和 ^ 取反;\d \w \s 及大写取反版本是高频缩写,注意 \w 的真实边界。下一节给字符「加数量」:量词。