no-useless-backreference
禁止正则表达式中无用的反向引用
✅ 推荐
在配置文件中使用来自@eslint/js
的recommended
配置将启用此规则。
在 JavaScript 正则表达式中,在语法上允许定义对属于模式其他备选部分的组的反向引用,对出现在反向引用之后的组的反向引用,对包含该反向引用的组的反向引用,或者对位于否定环视内部的组的反向引用。但是,根据规范,在任何这些情况下,反向引用最终总是只匹配零长度(空字符串),而不管反向引用和组出现在哪个上下文中。
始终成功匹配零长度且无法匹配任何其他内容的反向引用是无用的。它们基本上被忽略,并且可以在不改变正则表达式行为的情况下删除。
var regex = /^(?:(a)|\1b)$/;
regex.test("a"); // true
regex.test("b"); // true!
regex.test("ab"); // false
var equivalentRegex = /^(?:(a)|b)$/;
equivalentRegex.test("a"); // true
equivalentRegex.test("b"); // true
equivalentRegex.test("ab"); // false
无用的反向引用可能是代码中的错误。它通常表示正则表达式无法按预期工作。
规则详情
此规则旨在检测并禁止正则表达式中的以下反向引用
- 对另一个备选方案中组的反向引用,例如
/(a)|\1b/
。在这种构造的正则表达式中,反向引用预期匹配在此时非参与组中捕获的内容。 - 对模式中稍后出现的组的反向引用,例如
/\1(a)/
。该组尚未捕获任何内容,并且 ECMAScript 不支持前向引用。在向后匹配的反向环视内部,情况相反,此规则禁止对同一反向环视中之前出现的组的反向引用,例如/(?<=(a)\1)b/
。 - 对同一组内组的反向引用,例如
/(\1)/
。与前面类似,该组尚未捕获任何内容,并且 ECMAScript 不支持嵌套引用。 - 对否定环视中组的反向引用,如果反向引用不在同一否定环视中,例如
/a(?!(b)).\1/
。否定环视(前瞻或后顾)仅在其模式无法匹配时才成功,这意味着该组已失败。
根据 ECMAScript 规范,上面列出的所有反向引用都是有效的,始终成功匹配零长度,并且无法匹配任何其他内容。因此,它们不会产生解析或运行时错误,也不会影响其正则表达式的行为。它们在语法上有效但无用。
对于来自其他语言的开发人员来说,这可能令人惊讶,在其他语言中,其中一些反向引用可以以有意义的方式使用。
// in some other languages, this pattern would successfully match "aab"
/^(?:(a)(?=a)|\1b)+$/.test("aab"); // false
此规则的错误代码示例
在游乐场中打开
/*eslint no-useless-backreference: "error"*/
; // reference to (a) into another alternative
; // reference to (a) into another alternative
; // reference to (c) into another alternative
; // forward reference to (a)
; // forward reference to (b)
; // forward reference to (c)
; // forward reference to (?<foo>a)
; // backward reference to (a) from within the same lookbehind
; // backward reference to (a) from within the same lookbehind
; // nested reference to (\1)
; // nested reference to ((a)\1)
; // nested reference to (?<foo>(.)b\1)
; // reference to (b) into a negative lookahead
; // reference to (a) into a negative lookbehind
此规则的正确代码示例
在游乐场中打开
/*eslint no-useless-backreference: "error"*/
/^(?:(a)|(b)\2)$/; // reference to (b)
/(a)\1/; // reference to (a)
RegExp('(a)\\1(b)'); // reference to (a)
/(a)(b)\2(c)/; // reference to (b)
/(?<foo>a)\k<foo>/; // reference to (?<foo>a)
/(?<=\1(a))b/; // reference to (a), correctly before the group as they're in the same lookbehind
/(?<=(a))b\1/; // reference to (a), correctly after the group as the backreference isn't in the lookbehind
new RegExp('(.)\\1'); // reference to (.)
/^(?:(a)\1)$/; // reference to (a)
/^((a)\2)$/; // reference to (a)
/a(?<foo>(.)b\2)/; // reference to (.)
/a(?!(b|c)\1)./; // reference to (b|c), correct as it's from within the same negative lookahead
/(?<!\1(a))b/; // reference to (a), correct as it's from within the same negative lookbehind
请注意,此规则的目的是不检测并禁止正则表达式中反向引用语法的潜在错误用法,例如在字符类中使用或尝试引用不存在的组。根据上下文,\1
…\9
序列如果不是语法上有效的反向引用,可能会产生语法错误,或者被解析为其他内容(例如,作为旧版八进制转义序列)。
此规则的其他正确代码示例
在游乐场中打开
/*eslint no-useless-backreference: "error"*/
// comments describe behavior in a browser
/^[\1](a)$/.test("\x01a"); // true. In a character class, \1 is treated as an octal escape sequence.
/^\1$/.test("\x01"); // true. Since the group 1 doesn't exist, \1 is treated as an octal escape sequence.
/^(a)\1\2$/.test("aa\x02"); // true. In this case, \1 is a backreference, \2 is an octal escape sequence.
相关规则
版本
此规则是在 ESLint v7.0.0-alpha.0 中引入的。