RegEx в PHP: сопоставление с шаблоном вне неэкранированных кавычек - PullRequest
0 голосов
/ 19 мая 2009

Я пишу метод для извлечения определенных данных из строки запроса SQL, и мне нужно регулярное выражение сопоставлять любое слово внутри фигурных скобок ТОЛЬКО, когда оно появляется вне одинарных кавычек. Мне также нужно учесть вероятность экранированных (предшествующих обратной косой черты) кавычек, а также экранированных обратной косой черты.

В следующих примерах мне нужно, чтобы регулярное выражение совпадало с {FOO}, а не {BAR}:

blah blah {FOO} blah 'I\'m typing {BAR} here with an escaped backslash \\'
blah blah {FOO} 'Three backslashes {BAR} and an escaped quote \\\\\\\' here {BAR}'

Я использую preg_match в PHP, чтобы получить слово в фигурных скобках (в данном случае "FOO"). Вот строка с регулярным выражением, которая у меня есть:

$regex = '/' .
    // Match the word in braces
    '\{(\w+)\}' .
    // Only if it is followed by an even number of single-quotes
    '(?=(?:[^\']*\'[^\']*\')*[^\']*$)' .
    // The end
    '/';

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

Регулярное выражение, которое я предоставил, является на 100% успешным, ИСКЛЮЧЕНИЕМ для учета экранированных кавычек. Мне просто нужно убедиться, что перед совпадением в кавычках нет нечетного числа обратных слешей, но, судя по всему, я не могу передать это в RegEx. Любой берущий?

Ответы [ 3 ]

1 голос
/ 19 мая 2009

Способ работы с экранированными кавычками и обратными слешами состоит в том, чтобы использовать их в согласованных парах.

(?=(?:(?:(?:[^\'\\]++|\\.)*+\'){2})*+(?:[^\'\\]++|\\.)*+$)

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

p.s., Обратите внимание на либеральное использование собственнических квантификаторов (*+ и ++); без них у вас могут возникнуть проблемы с производительностью, особенно если целевые строки большие. Кроме того, если строки могут содержать разрывы строк, вам может потребоваться выполнить сопоставление в режиме DOTALL (он же режим «singleline» или «/ s»).

Однако я согласен с mmyers: если вы пытаетесь проанализировать SQL, вы столкнетесь с проблемами, которые регулярные выражения вообще не могут решить. Из всех вещей, с которыми плохо справляются регулярные выражения, SQL является одним из худших.

0 голосов
/ 20 мая 2009

Если вы действительно хотите использовать регулярные выражения для этого, я бы сделал это в два шага:

  1. Отделите строки от не строки с preg_split:

    $re = "('(?:[^\\\\']+|\\\\(\\\\\\\\)*.)*')";
    $parts = preg_split('/'.$re.'/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    
  2. Заменить все, что в строках :

    foreach ($parts as $key => $val) {
        if (preg_match('/^'.$re.'$/', $val)) {
            $parts[$key] = preg_replace('/\{([^}]*)}/', '$1', $val);
        }
    }
    

Но настоящий парсер, вероятно, был бы лучше, так как этот подход не настолько эффективен.

0 голосов
/ 20 мая 2009

Просто и, возможно, наивно, str_relace все ваши двойные обратные слеши. Затем str_replace вышел из одинарных кавычек. В этот момент сравнительно просто найти совпадения, которые не находятся в одинарных кавычках (например, используя существующее регулярное выражение)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...