no-useless-backreference
禁止在正则表达式中使用无用的反向引用
在 配置文件 中使用来自 @eslint/js 的 recommended 配置可以启用此规则
在 JavaScript 正则表达式中,从语法上讲,定义一个指向属于模式中另一个分支部分的分组的反向引用、指向出现在反向引用之后的分组的反向引用、指向包含该反向引用的分组的反向引用或指向位于负向环视内部的分组的反向引用都是有效的。然而,根据规范,在任何这些情况下,反向引用总是仅匹配零长度(空字符串),无论反向引用和分组出现的上下文如何。
🌐 In JavaScript regular expressions, it’s syntactically valid to define a backreference to a group that belongs to another alternative part of the pattern, a backreference to a group that appears after the backreference, a backreference to a group that contains that backreference, or a backreference to a group that is inside a negative lookaround. However, by the specification, in any of these cases the backreference always ends up matching only zero-length (the empty string), regardless of the context in which the backreference and the group appear.
总是成功匹配零长度且不能匹配其他任何内容的反向引用是无用的。它们基本上会被忽略,并且可以在不改变正则表达式行为的情况下移除。
🌐 Backreferences that always successfully match zero-length and cannot match anything else are useless. They are basically ignored and can be removed without changing the behavior of the regular expression.
const regex = /^(?:(a)|\1b)$/;
regex.test("a"); // true
regex.test("b"); // true!
regex.test("ab"); // false
const equivalentRegex = /^(?:(a)|b)$/;
equivalentRegex.test("a"); // true
equivalentRegex.test("b"); // true
equivalentRegex.test("ab"); // false
无用的反向引用可能是代码中的一个错误。它通常表示正则表达式未按预期工作。
🌐 Useless backreference is a possible error in the code. It usually indicates that the regular expression does not work as intended.
规则详情
🌐 Rule Details
此规则旨在检测并禁止正则表达式中的以下反向引用:
🌐 This rule aims to detect and disallow the following backreferences in regular expression:
- 对位于另一个备选方案中的分组的反向引用,例如,
/(a)|\1b/。在这样的构造的正则表达式中,反向引用预期匹配当时未参与的分组中所捕获的内容。 - 引用在模式中稍后出现的分组,例如
/\1(a)/。该分组尚未捕获任何内容,并且 ECMAScript 不支持前向引用。在向后匹配的回顾检查(lookbehind)中,情况相反,该规则不允许引用在同一回顾检查中先前出现的分组,例如/(?<=(a)\1)b/。 - 从同一组内对一个组的反向引用,例如
/(\1)/。与前面的类似,该组尚未捕获任何内容,且 ECMAScript 不支持嵌套引用。 - 对处于否定环视中的分组的反向引用,如果反向引用不在同一个否定环视中,例如,
/a(?!(b)).\1/。否定环视(前瞻或后顾)只有在其模式无法匹配时才会成功,这意味着该分组匹配失败。
根据 ECMAScript 规范,上述所有反向引用都是有效的,总是成功匹配零长度,并且不能匹配其他任何内容。因此,它们不会产生解析或运行时错误,但也不会影响其正则表达式的行为。它们在语法上是有效的,但毫无用处。
🌐 By the ECMAScript specification, all backreferences listed above are valid, always succeed to match zero-length, and cannot match anything else. Consequently, they don’t produce parsing or runtime errors, but also don’t affect the behavior of their regular expressions. They are syntactically valid but useless.
这可能会让来自其他语言的开发者感到惊讶,因为其中一些反向引用可以以有意义的方式使用。
🌐 This might be surprising to developers coming from other languages where some of these backreferences can be used in a meaningful way.
// in some other languages, this pattern would successfully match "aab"
/^(?:(a)(?=a)|\1b)+$/.test("aab"); // false
此规则的错误代码示例:
🌐 Examples of incorrect code for this rule:
/*eslint no-useless-backreference: "error"*/
/^(?:(a)|\1b)$/; // reference to (a) into another alternative
/^(?:(a)|b(?:c|\1))$/; // reference to (a) into another alternative
/^(?:a|b(?:(c)|\1))$/; // reference to (c) into another alternative
/\1(a)/; // forward reference to (a)
RegExp('(a)\\2(b)'); // forward reference to (b)
/(?:a)(b)\2(c)/; // forward reference to (c)
/\k<foo>(?<foo>a)/; // forward reference to (?<foo>a)
/(?<=(a)\1)b/; // backward reference to (a) from within the same lookbehind
/(?<!(a)\1)b/; // backward reference to (a) from within the same lookbehind
new RegExp('(\\1)'); // nested reference to (\1)
/^((a)\1)$/; // nested reference to ((a)\1)
/a(?<foo>(.)b\1)/; // nested reference to (?<foo>(.)b\1)
/a(?!(b)).\1/; // reference to (b) into a negative lookahead
/(?<!(a))b\1/; // reference to (a) into a negative lookbehind
符合此规则的正确代码示例:
🌐 Examples of correct code for this rule:
/*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 序列可能会产生语法错误,或者被解析为其他内容(例如,被解析为遗留的八进制转义序列)。
🌐 Please note that this rule does not aim to detect and disallow a potentially erroneous use of backreference syntax in regular expressions, like the use in character classes or an attempt to reference a group that doesn’t exist. Depending on the context, a \1…\9 sequence that is not a syntactically valid backreference may produce syntax error, or be parsed as something else (e.g., as a legacy octal escape sequence).
此规则的额外正确代码示例:
🌐 Examples of additional correct code for this rule:
/*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.
选项
🌐 Options
此规则没有选项。
🌐 This rule has no options.
相关规则
版本
此规则是在 ESLint v7.0.0-alpha.0 中引入。