RegEx w PHP: Dopasowywanie wzorca poza niewyspecjalizowanych uciekł cytatów

głosy
0

Piszę metody do zniesienia niektórych danych z ciąg kwerendy SQL, i muszę regex pasuje dowolne słowo wewnątrz nawiasów klamrowych tylko wtedy, gdy pojawia się na zewnątrz od pojedynczych cudzysłowach. Również trzeba to czynnik w możliwość zbiegłych (poprzedzone odwrotnym ukośnikiem) cytaty, a także uciekły ukośniki.

W poniższych przykładach, trzeba regex pasujące {foo} i nie {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}'

Używam preg_match w PHP, aby słowo w szelki ( „foo”, w tym przypadku). Oto ciąg regex mam dotąd:

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

Moja logika jest, że skoro jedyną rzeczą, mam parsowania jest ciągiem SQL prawna (oprócz Brace-którą dodałem), jeśli zestaw szelki następuje przez choćby liczbą nie uciekły cytatów, to musi być na zewnątrz cytatów.

Regex okażą się 100% sukcesem wyjątkiem biorąc pod uwagę notowania uciekli. Po prostu trzeba upewnić się, nie ma nieparzystą liczbę ukośniki przed meczem cytatem, ale dla życia mnie nie może wydawać się przekazać to w RegEx. Wszelkie chętnych?

Utwórz 19/05/2009 o 18:59
źródło użytkownik
W innych językach...                            


3 odpowiedzi

głosy
1

Sposób radzenia sobie ze zbiegłych cytatów i ukośniki jest, aby spożywać je parami.

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

Innymi słowy, jak skanowanie do następnego środki, pominąć jakąkolwiek parę znaków, który rozpoczyna się odwrotnym ukośnikiem. Który dba zarówno uciekł cytaty i uciekł backslashy. Ten uprzedzona pozwoli uciec znaków spoza cytowane sekcje, które prawdopodobnie nie jest konieczne, ale to chyba nie zaszkodzi.

ps zauważyć liberalny zastosowanie dzierżawczych kwantyfikatorów ( *+i ++); bez tych można mieć problemy z wydajnością, zwłaszcza gdy struny docelowymi są duże. Ponadto, jeśli łańcuchy mogą zawierać podziały wiersza, może trzeba zrobić dopasowanie w trybie dotall (aka „SingleLine” lub „/ s” Mode).

Jednak zgadzam się z mmyers: jeśli starasz się analizować SQL, to będzie napotkasz problemy, które nie mogą obsługiwać Wyrażenia regularne w ogóle. Ze wszystkich rzeczy, które Wyrażenia regularne są złe, SQL jest jednym z najgorszych.

Odpowiedział 19/05/2009 o 20:51
źródło użytkownik

głosy
0

Po prostu, a może naiwnie, str_replace wszystkie swoje podwójnych ukośników. Następnie str_replace się uciekły apostrofów. W tym momencie jest to stosunkowo proste, aby znaleźć rekordy, które nie są między apostrofami (przy użyciu istniejącego regex, na przykład).

Odpowiedział 19/05/2009 o 21:01
źródło użytkownik

głosy
0

Jeśli naprawdę chcesz używać wyrażeń regularnych do tego, by to zrobić w dwóch etapach:

  1. Oddzielić ciągi od nie-strun z preg_split:

    $re = "('(?:[^\\\\']+|\\\\(\\\\\\\\)*.)*')";
    $parts = preg_split('/'.$re.'/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    
  2. Wymień cokolwiek w ciągi :

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

Ale prawdziwy parser będzie prawdopodobnie lepiej jak takie podejście nie jest efektywne.

Odpowiedział 19/05/2009 o 21:24
źródło użytkownik

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