语法速查
1
2
3
|
/ pattern / flags
↑ ↑ ↑
起始符 匹配规则 修饰标志
|
标志
1
2
3
4
5
6
|
i // 不区分大小写
g // 搜索全部匹配项
m // 多行模式
u // Unicode
y // 必须从 lastIndex 处开始匹配,否则失败
s // 允许点 . 匹配换行符 \n
|
匹配规则
字符类是集合类的缩写
- \d —— 和 [0-9] 相同,
- \w —— 和 [a-zA-Z0-9_]相同,
- \s —— 和 [\t \n \v \f \r ] 外加少量罕见的 Unicode 空格字符相同。
- . ——匹配除换行符 (\n, \r, \u2028, \u2029) 之外的任意单个字符。
符号 |
名称 |
解释 |
[…] |
集合 |
搜索给定字符中的任意一个 [a-f] 表示从 a 到 f 范围内的字符 |
[^…] |
排除范围 |
匹配所有 除了给定的字符 之外的任意字符 |
{n |
具体数量(量词) |
\d{5} \d{3,5}查3到5位 \d{3,} 查大于等于 3 |
+ |
>1(量词) |
与 {1,} 相同 |
? |
<=1(量词) |
与 {0,1} 相同 |
? |
惰性模式 |
跟在量词后生效,/".+?"/g 将匹配的模式从贪婪转为惰性 |
* |
任意数量(量词) |
与 {0,} 相同 |
(…) |
捕获组 |
go+ 匹配goooo 或 goooooooo (go)+ 匹配 go,gogo,gogogo |
\N |
引用前面第 N 个捕获组的内容 |
\1找到第一个 (X) 并记住其内容。 |
| |
选择 |
html|php|java(script)? |
断言
用来判断某个位置前后是否满足特定条件,匹配到的内容并不包含这些断言本身
边界断言:
断言 |
名称 |
示例 |
^ |
确定行首 |
/^abc/m 可匹配每一行开头的 abc |
$ |
确定行尾 |
/abc$/m 匹配行末的 abc |
\b |
单词边界(word boundary) |
/\bcat\b/ 匹配独立的单词“cat” |
\B |
非单词边界 |
/\Bcat\B/ 不匹配独立的单词,只匹配内部“cat” |
还有一种断言用于判断一个位置的前后文本是否满足条件,感觉结合用例方法来看更好,放下面match里了。
字符串实例方法
match
match对“捕获组”(capturing groups)有两种完全不同的表现
没有g时:
1
2
3
4
5
6
7
8
9
10
11
|
const m = '2025-10-09'.match(/(\d{4})-(\d{2})-(\d{2})/)
/*
m 是一个类数组对象:
m[0] === '2025-10-09' // 整体匹配
m[1] === '2025' // 第1个捕获组
m[2] === '10' // 第2个捕获组
m[3] === '09' // 第3个捕获组
m.index // 匹配起始下标
m.input // 原字符串
m.groups // 若使用了“命名捕获组”,这里是个对象
*/
|
有 g:返回“所有整体匹配”,不包含捕获组
1
2
|
'2025-10-09'.match(/\d{2}/g) // ['20','25','10','09']
'2025-10-09'.match(/(\d{4})-(\d{2})-(\d{2})/g) // ['2025-10-09'] ← 只有整体匹配,没有 m[1]/m[2]/m[3]
|
matchAll 有“全局匹配”和“捕获组”
1
2
3
4
|
const it = 'a1b22c333'.matchAll(/([a-z])(\d+)/g)
for (const m of it) {
console.log(m[0], m[1], m[2]) // 整体、组1、组2
}
|
配合先行/后行断言使用
- 肯定前瞻 (?=X):当前位置后面必须是 X
- 否定前瞻 (?!X):当前位置后面不能是 X
- 肯定后顾 (?<=X):当前位置前面必须是 X
- 否定后顾 (?<!X):当前位置前面不能是 X
1
2
3
4
5
6
7
8
|
// 只匹配“foo 后面是 bar”的 foo
"foo bar foo baz".match(/foo(?=\sbar)/g); // ["foo"]
// 只匹配“foo 后面不是 bar”的 foo
"foo bar foo baz".match(/foo(?!\sbar)/g); // ["foo"](第二个)
// 只匹配“前面是 $ 的数字”(剥离货币符号)
"$123 and 456".match(/(?<=\$)\d+/g); // ["123"]
// 只匹配“前面不是字母的数字”
"a123 456".match(/(?<![A-Za-z])\d+/g); // ["456"]
|
后顾必须是“固定长度”
断言匹配到的内容并不包含这些断言本身,方便与 replace / split 结合(“在……前/后”插入/切分)使用
replace
1
2
3
4
5
6
7
|
let str = "We will, we will rock you"
const out1 = str.replace(/we/i, "$&...")
console.log(out1)
// We... will, we will rock you
const out2 = str.replace(/we/ig, "$&...")
console.log(out2)
// We... will, we... will rock you
|
更通用的方案是对replace的第二个参数使用回调,配合捕获组
replace(regexp, (match, p1, p2, …, offset, string, groups) => string)
- match:整段匹配
- p1/p2…:对应捕获组
- offset:匹配在原串中的起始下标
- string:原始字符串
- groups:命名分组((?<name>…))对象
用命名分组重排日期
1
2
3
4
5
|
const s = "Due: 2025-10-09";
const out = s.replace(/(\d{4})-(\d{2})-(\d{2})/, (match, y, m, d) => {
return `${d}/${m}/${y}`;
});
console.log(out); // "Due: 09/10/2025"
|
十六进制颜色转为 rgb
1
2
3
4
5
6
7
8
9
|
const s = "Primary: #1e90ff; Shadow: #000;";
const out = s.replace(/#([0-9a-f]{3}|[0-9a-f]{6})\b/gi, (m, hex) => {
if (hex.length === 3) hex = hex.split("").map(x => x + x).join("");
const r = parseInt(hex.slice(0,2), 16);
const g = parseInt(hex.slice(2,4), 16);
const b = parseInt(hex.slice(4,6), 16);
return `rgb(${r}, ${g}, ${b})`;
});
console.log(out); // "Primary: rgb(30, 144, 255); Shadow: rgb(0, 0, 0);"
|
额外:
十进制值转其他进制(以字符串形式表示),最方便就是toString()
1
2
3
|
const n = parseInt("101010", 2); // 42 字符串(某进制) -> 十进制数
(42).toString(2) // "101010"
(42).toString(8) // "52"
|
替换独立词并做词典映射
1
2
3
4
5
6
7
8
|
const dict = { js: "JavaScript", css: "Cascading Style Sheets" };
const s = "I like JS, css and JSON (not js-on).";
const out = s.replace(/\b(js|css)\b/gi, (m) => {
const v = dict[m.toLowerCase()];
return v ?? m; // 映射不到就原样返回
});
console.log(out);
// "I like JavaScript, Cascading Style Sheets and JSON (not js-on)."
|
split
注意事项:
g 标志对 split 没意义:split 会自己反复匹配分隔符
捕获组会进结果:想保留分隔符就用 (),不想保留就别加或者用非捕获组(?:X)
按任意空白切割
1
2
|
" foo\tbar baz ".trim().split(/\s+/);
// ["foo", "bar", "baz"]
|
保留分隔符
1
2
|
"1,2;3|4".split(/([,;|])/);
// ["1", ",", "2", ";", "3", "|", "4"]
|
用limit控制切割次数
1
2
3
4
5
|
"a,b,c,d".split(/,/, 2);
// ["a", "b"]
"2025-10-09".split(/-/, 2);
// ["2025", "10"] // 第3段被丢弃
|
正则表达式方法
test
比如,用来判断单个字符是否在某个范围
1
2
3
4
|
/^[a-z]$/i.test(ch) // 英文字母(大小写,i 不区分大小写)
/^[0-9]$/.test(ch) // 数字
/^[A-F0-9]$/.test(ch) // 十六进制字符(大写)
/^[a-z]+$/i.test(str) // 整个字符串是否只由这些字符组成
|
exec
返回一次详细的匹配结果对象或 null
当正则带有 g 标志时,exec() 会记住上次匹配的位置lastIndex,
从而可以循环执行多次,逐步提取所有匹配
复习资料
练习用:
RegexOne 中文
regex101