RegEx em PHP: Matching um padrão fora de citações não escapou

votos
0

Eu estou escrevendo um método para levantar alguns dados a partir de uma seqüência de consulta SQL, e eu preciso regex corresponde a qualquer palavra dentro de chaves somente quando ele aparece fora de aspas simples. Eu também precisam de levar em consideração a possibilidade de escape (precedido de barra invertida) citações, bem como barras invertidas escaparam.

Nos exemplos a seguir, eu preciso do regex para corresponder {FOO} e não {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}'

Eu estou usando preg_match em PHP para obter a palavra nas chaves ( FOO, neste caso). Aqui está a seqüência de regex eu tenho até agora:

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

Minha lógica é que, já que a única coisa que eu sou analisar é uma string SQL legal (além da cinta-coisa que eu adicionado), se um conjunto de chaves é seguido por um mesmo número de citações não escaparam, então ele deve estar fora de citações.

A regex que eu forneci é 100% bem sucedida, exceto para tomar citações escaparam em consideração. Eu só preciso ter certeza de que não há número ímpar de barras invertidas antes de uma partida de citação, mas para a vida de mim eu não consigo transmitir isso em RegEx. Algum comprador?

Publicado 19/05/2009 em 18:59
fonte usuário
Em outras línguas...                            


3 respostas

votos
1

A maneira de lidar com citações e barras invertidas escaparam é consumi-los em pares correspondentes.

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

Em outras palavras, como você digitalizar para a próxima citação, você pular qualquer par de caracteres que começa com uma barra invertida. Que cuida de ambos escaparam aspas e escapou barras invertidas. Esta antecipação vai permitir caracteres escapou fora de seções citadas, o que provavelmente não é necessária, mas provavelmente não vai doer tanto.

ps, Observe o uso liberal de quantificadores possessivo ( *+e ++); sem aqueles que você pode ter problemas de desempenho, especialmente se as cordas alvo são grandes. Além disso, se as cordas podem conter quebras de linha, você pode precisar de fazer a correspondência no modo dotall (aka, "Singleline" ou "/ s" modo).

No entanto, concordo com mmyers: se você está tentando analisar SQL, você vai correr em problemas que expressões regulares não conseguem lidar com a todos. De todas as coisas que expressões regulares são maus no, SQL é um dos piores.

Respondeu 19/05/2009 em 20:51
fonte usuário

votos
0

Se você realmente quiser usar expressões regulares para isso, eu iria fazê-lo em duas etapas:

  1. Separe as cordas dos não-strings com preg_split:

    $re = "('(?:[^\\\\']+|\\\\(\\\\\\\\)*.)*')";
    $parts = preg_split('/'.$re.'/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    
  2. Substituir o que quer nas cordas :

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

Mas um verdadeiro analisador provavelmente seria melhor como esta abordagem não é tão eficiente.

Respondeu 19/05/2009 em 21:24
fonte usuário

votos
0

Simplesmente, e talvez ingenuamente, str_replace fora todas as suas barras invertidas duplas. Então str_replace fora aspas simples escaparam. Nesse ponto, é relativamente fácil encontrar jogos que não estão entre aspas simples (usando seu regex existente, por exemplo).

Respondeu 19/05/2009 em 21:01
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more