Как регулярное выражение может игнорировать экранированные кавычки при сопоставлении строк?

Я пытаюсь написать регулярное выражение, которое будет соответствовать всему, НО апостроф, который не был экранирован. Учтите следующее:

<?php $s = 'Hi everyone, we\'re ready now.'; ?>

Моя цель - написать регулярное выражение, которое будет соответствовать его строковой части. Я думаю о чем-то вроде

/.*'([^']).*/

чтобы соответствовать простой строке, но я пытался выяснить, как получить отрицательный взгляд назад, работая над этим апострофом, чтобы убедиться, что ему не предшествует обратная косая черта ...

Любые идеи?

- JMT


person JMTyler    schedule 29.06.2009    source источник


Ответы (4)


<?php
$backslash = '\\';

$pattern = <<< PATTERN
#(["'])(?:{$backslash}{$backslash}?+.)*?{$backslash}1#
PATTERN;

foreach(array(
    "<?php \$s = 'Hi everyone, we\\'re ready now.'; ?>",
    '<?php $s = "Hi everyone, we\\"re ready now."; ?>',
    "xyz'a\\'bc\\d'123",
    "x = 'My string ends with with a backslash\\\\';"
    ) as $subject) {
        preg_match($pattern, $subject, $matches);
        echo $subject , ' => ', $matches[0], "\n\n";
}

отпечатки

<?php $s = 'Hi everyone, we\'re ready now.'; ?> => 'Hi everyone, we\'re ready now.'

<?php $s = "Hi everyone, we\"re ready now."; ?> => "Hi everyone, we\"re ready now."

xyz'a\'bc\d'123 => 'a\'bc\d'

x = 'My string ends with with a backslash\\'; => 'My string ends with with a backslash\\'
person VolkerK    schedule 29.06.2009
comment
Голосование, потому что вы предоставили тестовые примеры. - person the.jxc; 30.06.2009

Вот мое решение с тестовыми примерами:

/.*?'((?:\\\\|\\'|[^'])*+)'/

И мое (Perl, но я не использую никаких специфических для Perl функций, я не думаю) доказательство:

use strict;
use warnings;

my %tests = ();
$tests{'Case 1'} = <<'EOF';
$var = 'My string';
EOF

$tests{'Case 2'} = <<'EOF';
$var = 'My string has it\'s challenges';
EOF

$tests{'Case 3'} = <<'EOF';
$var = 'My string ends with a backslash\\';
EOF

foreach my $key (sort (keys %tests)) {
    print "$key...\n";
    if ($tests{$key} =~ m/.*?'((?:\\\\|\\'|[^'])*+)'/) {
        print " ... '$1'\n";
    } else {
        print " ... NO MATCH\n";
    }
}

Запуск этого шоу:

$ perl a.pl
Case 1...
 ... 'My string'
Case 2...
 ... 'My string has it\'s challenges'
Case 3...
 ... 'My string ends with a backslash\\'

Обратите внимание, что начальный подстановочный знак в начале не должен быть жадным. Затем я использую совпадения без возврата, чтобы проглотить \\ и \ ', а затем все остальное, что не является автономным символом кавычек.

Я думаю, что этот, вероятно, имитирует встроенный подход компилятора, что должно сделать его довольно пуленепробиваемым.

person the.jxc    schedule 29.06.2009

/.*'([^'\\]|\\.)*'.*/

Часть в скобках ищет символы без апострофа / обратной косой черты и экранированные символы обратной косой черты. Если можно экранировать только определенные символы, измените \\. на \\['\\a-z] или что-то еще.

person John Kugelman    schedule 29.06.2009
comment
Очень близко, но это не касается патологического случая ... 'Моя строка заканчивается обратной косой чертой \\' - person the.jxc; 30.06.2009
comment
Спасибо, Джон! К счастью для меня, случаи, с которыми мне придется иметь дело, можно ограничить, и они никогда не дойдут до проблемы, описанной в файле .jxc. Очень простое решение, о котором я действительно должен был подумать. Еще раз спасибо! :) - person JMTyler; 30.06.2009

Это для JavaScript:

/('|")(?:\\\\|\\\1|[\s\S])*?\1/

it...

  • соответствует строкам в одинарных или двойных кавычках
  • соответствует пустым строкам (длина 0)
  • соответствует строкам со встроенными пробелами (\n, \t и т. д.)
  • пропускает внутренние экранированные кавычки (одинарные или двойные)
  • пропускает одинарные кавычки внутри двойных кавычек и наоборот

Захватывается только первая цитата. Вы можете записать строку без кавычек в $ 2 с помощью:

/('|")((?:\\\\|\\\1|[\s\S])*?)\1/

person aMarCruz    schedule 02.07.2015