正则里哪些字符要转义:字符类里外是两套规则

正则里哪些字符要转义:字符类里外是两套规则

正则的转义规则容易陷入两种极端:要么见到符号就加反斜杠(正则变得没法读),要么凭印象加(漏掉关键的那个)。

其实规则很清楚,只是它分三处,而且三处不一样。

一、模式里:12 个元字符

在正则模式中(字符类外面),这些字符有特殊含义,想匹配它们本身就要转义:

. ^ $ * + ? ( ) [ ] { } | \

字符含义.任意字符^ $行首 / 行尾锚点* + ?量词{ }次数量词 {2,5}( )分组[ ]字符类|或\转义符本身

最常被漏掉的是点号。匹配 IP 地址、域名、文件扩展名时,. 不转义就成了「任意字符」:

/1.2.3.4/ 匹配 "1x2y3z4" ✗

/1\.2\.3\.4/ 只匹配 "1.2.3.4" ✓

除此之外的字符——/ , ; : ' " - _ @ # % & = < > 等等——都不是元字符,不需要转义。给它们加反斜杠不会报错,但会让正则变难读。

二、字符类里面:规则完全不同

这是最容易记混的一处:方括号里面,绝大多数元字符都失去特殊含义。

[.*+?] ← 匹配点、星号、加号、问号这四个字符本身

不需要任何转义。

类内真正需要当心的只有四个:

字符规则\永远要转义]要转义,或者放在第一个位置^只在第一个位置表示取反,其他位置是字面量-在两个字符中间表示范围;放在首位或末位就是字面量

所以下面这些都是合法且常见的写法:

[a-z-] ← 小写字母,加上横杠本身(横杠在末位)

[-a-z] ← 同上(横杠在首位)

[a^b] ← 匹配 a、^、b(脱字符不在首位)

[]a] ← 匹配 ] 或 a(右括号在首位)

一个实用习惯:想匹配横杠时把它放在末位,比写 \- 更常见,也更容易一眼看懂。

三、替换字符串里:那个 $

这一处最容易出事,因为它和正则模式是两套完全不同的语法。

JS 的替换串里,$ 是特殊字符:

写法含义$&整段匹配到的内容$1 $2第一、第二个捕获组$`匹配位置之前的全部文本$'匹配位置之后的全部文本$$一个字面的美元符号

典型事故:把价格 $100 作为替换内容写进去。

'价格'.replace(/价格/, '$100')

// $1 被当成第一个捕获组,结果是「组的内容 + 00」

两种避法:

替换内容含 $ 时写成 $$

更稳的做法是用函数形式:

str.replace(re, () => 用户提供的内容) // 返回值不做任何 $ 解释

其他语言的替换串用 \1 这类反斜杠语法,反斜杠同样要按各自的规则转义。

四、动态拼接:必须调转义函数

把变量拼进正则,是这四处里唯一会造成安全问题的。

const re = new RegExp(userInput); // ✗ 危险

三种后果:

语义错误 —— 用户搜 1+1,被解释成「一个或多个 1,后面跟一个 1」

抛异常 —— 用户输入 (,正则语法错误

灾难性回溯 —— 精心构造的输入能让主线程卡住几秒到几分钟

各语言的转义函数:

语言函数Pythonre.escape()JavaPattern.quote()PHPpreg_quote()Goregexp.QuoteMeta()JavaScript没有内置(有 RegExp.escape 提案)

JS 通行的手写版是把这一组字符前面统一加反斜杠:

const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

判断原则很简单:正则里有一段来自变量时,问一句「这段是模式还是字面量」——是字面量就必须转义。

五、两层解析:new RegExp 的双反斜杠

/\d/ // 正则字面量,一个反斜杠

new RegExp("\\d") // 字符串构造,两个

原因:new RegExp 的参数先被字符串解析器处理一遍,再交给正则引擎。源码里的 "\\d" 变成两个字符 \ 和 d,正则引擎才看到「数字」这个含义。

写成 "\d" 会怎样?字符串解析时 \d 不是已知转义序列,多数 JS 引擎会宽容地当成 d——不报错,但正则变成了匹配字母 d。

推论:

能用正则字面量就用字面量,少一层解析

匹配一个反斜杠要写四个:new RegExp("\\\\")

从配置文件、数据库里读的正则字符串不经过源码解析,那里写一个反斜杠就够——这一点最容易和源码里的写法搞混

速查

位置需要转义的模式中. ^ $ * + ? ( ) [ ] { } | \字符类内\、]、首位的 ^、中间的 -替换串(JS)$(写成 $$),或改用函数形式字符串构造反斜杠再翻一倍

80 条语法的完整对照和方言差异标注在 正则语法速查;要验证一条表达式实际匹配到什么,用 Regex Pro。

相关

各方言之间的差异(\A、(?i)、后行断言) → PCRE / POSIX / JS / Python 的方言差异

灾难性回溯的成因与规避 → 正则的灾难性回溯

常用的十条现成模式 → 10 个最常用的正则

替换模板和跨语言导出 → 替换模板与跨语言导出

相关文章

淘宝店铺等级怎么划分的?怎么快速提升等级? 日博365备用网址

淘宝店铺等级怎么划分的?怎么快速提升等级?

📅 07-08 👁️ 523
世俱杯小组赛:切尔西胜突尼斯希望 日博365备用网址

世俱杯小组赛:切尔西胜突尼斯希望

📅 12-20 👁️ 1887
睹怎么读 365会提款不成功吗

睹怎么读

📅 09-04 👁️ 4375