标志位
标志位(flags)是写在正则后面的几个字母——它们不改变模式的"形状",但改变引擎的整体行为。比如该找全部还是只找一个、是否忽略大小写、点号是否匹配换行。这一章把 JS 里六个标志位一次讲清,并对照 Python/Java 的写法差异。
三大基础标志
这三个是日常最常用的,几乎每个正则都要考虑是否加它们:全局、忽略大小写、多行。
// 三大基础标志(必须背下来)
// g global 全局匹配:找出全部,默认只找第一个
"aaa".match(/a/); // ["a"] (只找一个)
"aaa".match(/a/g); // ["a","a","a"] (找全部)
"a1b2c3".replace(/\d/g, "X"); // "aXbXcX"
// i ignoreCase 忽略大小写
"Hello".match(/hello/); // null
"Hello".match(/hello/i); // ["Hello"]
// m multiline 多行模式:^ $ 匹配每行头尾(默认只匹配整串头尾)
"foo\nbar".match(/^bar/); // null
"foo\nbar".match(/^bar/m); // ["bar"]
// JS 写法:字面量末尾列标志
/hello/gi // 全局 + 忽略大小写,顺序无所谓
/^foo$/gm // 多行模式 + 全局
new RegExp("hello", "gi") // 字符串构造,第二个参数是标志- 全局 g:不加只匹配第一个,加了找全部。批量替换、统计次数必须加。
- 忽略大小写 i:大小写不敏感,搜索框、关键词过滤常用。
- 多行 m:让脱字符和美元匹配每行头尾,处理多行文本必备。
进阶标志
下面三个是现代 JS 才有的(ES6 之后),处理 Unicode、emoji、粘附匹配等高级场景。处理中文必须用 u 标志,否则正则会把汉字按字节拆开。
// 进阶标志(现代 JS / 高级场景)
// s dotall(别名 singleline):让 . 也匹配换行
/a.b/.test("a\nb"); // false (. 默认不匹配换行)
/a.b/s.test("a\nb"); // true (s 让 . 匹配任意字符)
// u unicode:正确处理 Unicode,中文/emoji 必备
/^.$/.test("𝌆"); // false (默认按 UTF-16 码元拆,emoji 是两个码元)
/^.$/u.test("𝌆"); // true (u 模式按码点处理)
/\w/.test("中"); // false (默认 \w 不含中文)
/\p{L}/u.test("中"); // true (u 模式支持 Unicode 属性转义)
// y sticky:粘附模式,从 lastIndex 位置精确匹配(不前进一步)
const re = /a/y;
re.lastIndex = 0; re.exec("abab"); // ["a"] 位置 0
re.lastIndex = 1; re.exec("abab"); // null 位置 1 是 b,不匹配也不前进
// 各标志出现的版本:
// g i m 最早就有(ES3)
// u y ES6(2015)
// s ES2018特别强调 Unicode 标志:它让你的正则正确处理 emoji 和非拉丁字符。处理中文姓名、内容审核、聊天消息——只要涉及中文或 emoji,默认的字符类(单词字符、点号)都可能失灵,加 u 才能正确工作。
标志组合
实际项目里标志几乎总是组合使用——全局加多行处理文本、全局加 Unicode 处理国际化内容。看几个真实组合:
// 标志组合与实际效果
// 1. gi 全局 + 忽略大小写:批量替换最常用
"Hello World".replace(/o/gi, "0"); // "Hell0 W0rld"
// 2. gm 全局 + 多行:批量处理每行
"text\n indented\n indented".replace(/^\s+/gm, "");
// "text\nindented\nindented" (删除每行行首空白)
// 3. gsu 处理中文/emoji 的全局搜索
"中文 emoji 😀 end".match(/\p{L}|\p{Emoji}/gu);
// ["中","文","e","m","o","j","i","😀","e","n","d"]
// 4. 不加 g 的 matchAll 报错(Python 风格迭代)
const re = /\w+/g;
"hello world".matchAll(re); // 返回迭代器
// 注意:matchAll 必须加 g,否则抛异常一个常见陷阱:matchAll 必须配合 g 标志,否则直接抛异常。这是 JS 设计上"防止误用"的保护——但新手第一次遇到会困惑。
跨语言差异
不同语言里写标志位的语法不同,但概念完全一致。这里对照 JS、Python、Java、PHP 四种主流写法,让你读其他语言的代码也不陌生。
// 不同语言的标志位差异
// JavaScript: 字面量 /pat/flags 或 new RegExp("pat", "flags")
/abc/gimu
// Python: re.compile 第二参数 flags,用按位或
// import re
// re.findall(r"abc", s, re.I | re.M | re.S)
// re.I 忽略大小写 re.M 多行
// re.S dotall re.U Unicode(Python3 默认开启)
// re.X 扩展(允许在模式里写空白和注释)
// Java: 模式末尾直接写标志字母
// Pattern.compile("abc", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
// 或内嵌 (?ism) 在模式开头
// PHP: 模式末尾用分隔符后写标志
// /abc/ismu
// 内嵌标志(?后跟字母):在模式中间改变标志
"Abc".match(/(?i)abc/); // JS 不支持这种内嵌写法,PCRE 支持
/(?i)abc/.test("ABC"); // PCRE/PHP 里 true,JS 里语法错误
// x 标志(扩展):允许模式里写空白和注释,大正则必备
const big = /\d{4} # 年
-\d{2} # 月
-\d{2} # 日
/x; // 注意 JS 不支持 x,PCRE/Python 才支持几个关键差异点:Python 用按位或连接常量、JS 用字母串联、PHP/PCRE 用分隔符后字母。还有一个特殊标志 x(扩展),允许在正则里写空白和注释,大正则必备——但 JS 不支持,只能靠构建字符串拼接加注释。
实用建议
- 表单校验:通常不加 g(只校验一次即可),加 i 看场景(邮箱用户名不区分大小写,密码则要区分)。
- 搜索替换:通常加 g(找全部)+ i(看是否忽略大小写)。
- 多行文本:加 m 处理每行头尾。
- 中文/emoji:加 u,避免按字节拆字符。
- 性能敏感:粘附 y 比全局 g 更快(无需扫描),适合词法分析。
小结
- 三大基础:全局、忽略大小写、多行,日常 90% 场景够用。
- 三大进阶:dotall、Unicode、sticky,处理现代字符集和高级场景。
- 中文/emoji 必须加 u,否则正则行为会出错。
- 跨语言写法不同,概念一致,可对照迁移。
下一章是实战篇——把前面所有概念串起来,写邮箱、手机号、URL、身份证等高频常用模式。
← 上一篇 零宽断言(环视)
下一篇 常用正则模式 →