版本

no-useless-backreference

不允許在正規表示式中使用無用的反向參考

建議

設定檔中使用來自 @eslint/jsrecommended 設定會啟用此規則

在 JavaScript 正規表示式中,語法上可以定義反向參考到屬於模式的另一個替代部分的群組、反向參考到出現在反向參考之後的群組、反向參考到包含該反向參考的群組,或反向參考到負向lookaround內的群組。然而,根據規範,在任何這些情況下,反向參考總是只匹配零長度(空字串),無論反向參考和群組出現在哪個上下文中。

總是成功匹配零長度且無法匹配任何其他內容的反向參考是無用的。它們基本上被忽略,並且可以移除而不會改變正規表示式的行為。

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

無用的反向參考可能是程式碼中的錯誤。它通常表示正規表示式無法如預期般運作。

規則詳細資訊

此規則旨在偵測並不允許在正規表示式中使用以下反向參考

  • 反向參考到另一個替代方案中的群組,例如 /(a)|\1b/。在如此建構的正規表示式中,反向參考預期匹配在該點未參與的群組中捕獲的內容。
  • 反向參考到稍後出現在模式中的群組,例如 /\1(a)/。該群組尚未捕獲任何內容,而且 ECMAScript 不支援前向參考。在向後匹配的 lookbehind 內,情況相反,此規則不允許反向參考到出現在同一 lookbehind 中之前的群組,例如 /(?<=(a)\1)b/
  • 從同一群組內反向參考到群組,例如 /(\1)/。與前一個類似,該群組尚未捕獲任何內容,而且 ECMAScript 不支援巢狀參考。
  • 反向參考到負向 lookaround 中的群組,如果反向參考不在同一個負向 lookaround 中,例如 /a(?!(b)).\1/。負向 lookaround(lookahead 或 lookbehind)只有在其模式無法匹配時才會成功,這表示該群組已失敗。

根據 ECMAScript 規範,上面列出的所有反向參考都是有效的,總是成功匹配零長度,並且無法匹配任何其他內容。因此,它們不會產生解析或執行階段錯誤,但也不會影響其正規表示式的行為。它們在語法上有效但無用。

對於來自其他語言的開發人員來說,這可能會令人驚訝,因為在其他語言中,其中一些反向參考可以用有意義的方式使用。

// in some other languages, this pattern would successfully match "aab"

/^(?:(a)(?=a)|\1b)+$/.test("aab"); // false

此規則的不正確程式碼範例

在 Playground 中開啟
/*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

此規則的正確程式碼範例

在 Playground 中開啟
/*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 序列可能會產生語法錯誤,或被解析為其他內容(例如,作為舊式的八進位逸出序列)。

此規則的其他正確程式碼範例

在 Playground 中開啟
/*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 中引入。

延伸閱讀

資源

變更語言