版本

no-useless-backreference

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

推薦

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

在 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

此規則的錯誤程式碼範例

在 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 中引入。

延伸閱讀

資源

變更語言