бесполезные обратные ссылки
Запретить бесполезные обратные ссылки в регулярных выражениях
Использование конфигурации recommended из @eslint/js в файле конфигурации файл конфигурации включает это правило
В 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.
Дополнительные материалы
Источники
© OpenJS Foundation and other contributors
Licensed under the MIT License.
https://eslint.org/docs/latest/rules/no-useless-backreference