Подтвердить что ты не робот

Есть ли случай, когда "[^ xy]" не равно "(?! X | y)."?

Я работаю над своей собственной библиотекой JavaScript для поддержки новых метасимволов и функций для регулярных выражений, и я хотел бы найти случай, когда [^xy] не эквивалентен (?!x). (или, более конкретно, (?:(?!x|y).)).

Возьмем пример текста: "abc\n"

Скажем, я хочу эмулировать регулярное выражение Perl: /\A.{3}\Z/s

С флагом singleline регулярное выражение JavaScript должно быть эквивалентно: /^[\s\S]{3}\n*$(?!\s)/ (\A становится ^, . становится [\s\S], \Z становится \n*$(?!\s))

Теперь /^.{3}$/ завершится с ошибкой, но /^[\s\S]{3}\n*$(?!\s)/ будет захватывать "abcabc" (так же, как и регулярное выражение Perl)

Так как \Z содержит больше, чем просто метасимвол, эмуляция [^\Z] представляется сложнее.

Возьмем пример текста: "abcabc\n"

Предложенное регулярное выражение JavaScript для регулярного выражения Perl /.{3}[^\Za]/g будет .{3}(?:(?!\n*$(?!\s)|a).)/g

Оба будут соответствовать "bcab"

Итак, наконец, я снова задаю вопрос. Есть ли случай, когда [^xy] не эквивалентен (?:(?!x|y).) с таким сценарием, возможно, в более сложном регулярном выражении, где lookahead изменит сценарий?

4b9b3361

Ответ 1

Есть ли случай, когда [^xy] не равно (?!x|y).?

Только тот, который вы уже описали: Точка JS не соответствует символам новой строки и должна быть заменена на [\s\S].

\Z становится \n$(?!\s)

Это выглядит неправильно. После окончания строки (\Z/$) никогда не будет ничего, независимо от того, пробелы или нет. Afaik, \Z - это утверждение с нулевой шириной (оно не потребляет новую строку (строки)) и должно быть эквивалентно

(?=\n*$)
//   ^ not sure whether ? or *

Так как \Z содержит больше, чем просто метасимвол, эмуляция [^\Z] представляется более сложной.

Что вы подразумеваете под "метасимволом"? Это утверждение с нулевой шириной и не имеет особого смысла в классе символов. Я бы предположил, что это либо синтаксическая ошибка, либо будет интерпретирована буквально (неэкранированная) как [^Z].

Ответ 2

Для строки ввода "x\na" 2 регулярных выражения выдают разные выходы, потому что . не соответствует символам новой строки.

console.log("x\na".match(/(?:(?!x|y).)/))
["a", index: 2, input: "x↵a"]
console.log("x\na".match(/[^xy]/))
["↵", index: 1, input: "x↵a"]

Если вы меняете . на [\s\S], в этом случае вывод идентичен:

console.log("x\na".match(/(?:(?!x|y)[\s\S])/))
["↵", index: 1, input: "x↵a"]

Я не могу сейчас думать ни о каком другом случае.

Ответ 3

[^xy] будет соответствовать \n. (?!x|y). по умолчанию не соответствует \n (поскольку . не соответствует \n)

Я не верю, что у javascript есть модификатор "dotall" или "single-line", но с новыми версиями каждого браузера, который ударяет каждые пару месяцев, я потерял трек.

Ответ 4

Как говорили другие, вы должны использовать [\s\S] вместо . в замене. В противном случае, если вы делаете это преобразование только через литеральные строки, вам нужно еще кое-что позаботиться. В частности, метасимволы и escape-последовательности:

[^*)] => (?!\*|\))[\s\S]

Но я думаю, вам все равно нужно позаботиться о разборе и написании мета-персонажей.

Самый сложный из них, вероятно, \b, хотя, потому что это символ (обратное пространство) в классах символов и граница слова снаружи. Поэтому при замене вам придется идти с восьмеричным или шестнадцатеричным побегом:

[^a\b] => (?!a|\10)[\s\S] 
    or => (?!a|\x08)[\s\S]

Кроме этого, они должны быть всегда эквивалентными.

Ответ 5

Случай, когда формат [^xy] не совпадает с (?:(?!x|y).), где x было утверждением с нулевой шириной, а не фактическим символом, например:

Учитывая этот образец текста: ab-yz

Regex: [^\by] Пример: http://www.rubular.com/r/ERKrqyeAs9

Возвращает:

[0] => a
[1] => b
[2] => -
[3] => z

В то время как

Regex: (?:(?!\b|y).) example: http://www.rubular.com/r/V5RdyQEQo5

Возвращает:

[0] => b
[1] => z

Другие неэквивалентные выражения, они в основном фокусируются на том факте, что тот же синтаксис имеет разные значения внутри или вне класса символов:

  • [^^y] дает a, b, -, z не равно (?:(?!^|y).), дает b, -, z
  • [^.y] дает a, b, -, z не равно (?:(?!.|y).) ничего не дает

Или вы можете попробовать это в юникодном саморождении в Perl: http://ideone.com/2xMfkQ

print "\ncapture\n";
@m = ("ss" =~ m/^(?:(?!\xDF|y).)+$/ui ); 
print for @m;

print "\nclass\n";
@m = ("ss" =~ m/^[^\xDFy]+$/ui) ; 
print for @m;

Урожайность:

capture

class
1