2012-01-31 9 views
1

環境:PHP 5.3文字列/コメントの中にないパターンに一致する方法は?

私は独自のクエリパラメータ置換メソッドを作成しようとしています。

select * from xxx where a=? and b>? 

、すべての?パラメータの値が既知であると仮定して、当然のことながら

select * from xxx where a=1 and b>2 

に変換します。基本的に私はこれをしたいです。 OK、それはちょっと単純ですが、質問には十分です。

だから、私がする必要があるのは、指定された文字列のすべての?マークを見つけることです。簡単だよね?しかし、一つのキャッチがあります:私は文字列やコメントの中にあるマークを探したくありません。だから、この文字列で:

select * -- I know * is bad, but just once can't hurt, right? 
from xxx /* ? */ where a=? and b='Question?' 

?マークの一つだけを交換する必要があります。

私の直感は、PHPのpreg_replace()になるはずですが...私の正規表現の知識は適切なパターンを構築するのに失敗します。私はそれを "手で"解析することもできますが、パフォーマンスが不適切なヒットになるのではないかと心配しています。 )、または私はそれを手動で文字単位で解析する必要がありますか?

+0

これは単なる楽しいのですか、これには理由がありますか?なぜ個人的なパラメータフレームワークが必要なのですか? – Nanne

+0

これはどのようなSQL方言ですか? – Gumbo

+0

クエリ内のコメントを許可するので、あなたはそれをさらに難しくしました。 –

答えて

0

これは正規表現にとっては難しい問題ですが、パーサーがより適していますが、特定の制約が満たされている限り、正規表現は機能します。以下のとおりです。

  • ネストされたコメントは
  • 何が文字列内の引用符をエスケープしない
  • 単一引用符の内側
  • すべての引用符やコメントが正しくバランスしている文字列内の
  • はコメント区切り文字をコメントはありませ
  • たものがケースであれば、あなたが

を指定することができ、最大行の長さがあります、あなたは単に

  • で(同じ行に)付いていない?を探すことができます0。 /*は、100の行の最大長を想定すると最初の引用符の偶数続い

を発生しない限り、これはあなたが試すことがあなたに

$result = preg_replace(
    '%(?<!--.{0,100}) # Assert no -- preceding on this line 
    \?     # Match a ? 
    (?!     # Assert that it\'s impossible to match... 
    (?s:    # (allowing the dot to match newlines here): 
     (?!/\*)   # (and making sure there is no intervening /*) 
     .     # any character 
    )*     # zero or more times, if that string is followed by 
    \*/     # */ 
    )     # End of lookahead 
    (?=     # Assert that it *is* possible to match 
    (?:     # the following regex: 
     [^\']*\'[^\']*\' # a string containing exactly two quotes 
    )*     # repeated zero or more times 
    [^\']*    # followed by only non-quote characters 
    $     # until the end of the string. 
    )     # End of lookahead. 
    %x', 
    'REPLACE', $subject); 
+0

これは長いリストですが、実際には、すべての理由は、それを投げ入れることができるようにし、可能な限り多くのことを理解することです。私は正規表現は今度は仕事のための正しいツールではないと思います! –

1

を与える*/が続いていない

  • 最初にコメント内のすべての疑問符を削除し、それらを覚えて、プレースホルダをクエリに入れ、preg_replace()でクエリを解析し、プレースホルダがあるところのコメントに疑問符を挿入します。 は、私は他の誰かがよりエレガントな解決策があるかもしれませんが、私の最初の本能は完全にコメントを取り除くために正規表現を使用することで、その後、パターンマッチパラメータ

    $matches = array(); 
    preg_match_all('/\/\*.*?.*\*\//U', $query, $matches); 
    preg_replace('/\/\*.*?.*\*\//U', $arrayWithIndicesOfParameters, $query); 
    preg_replace(/*your replacement of parameters*/); 
    preg_replace($arrayWithIndicesOfParameters, $matches, $query); //str_replace should be sufficient here 
    
  • 0

    ようかなっ意味します。

    $expressions = array(
        "#/\*(.*)\*/#", 
        "#[-]{2}(.*)\\n#", 
    ); 
    $query = preg_replace($expressions, "", $query); 
    
    0

    私はおそらくこれを行うだろう:

    • は、文字列構文とコメント構文ごとに、正規表現を検索します。
    • これらを組み合わせて、文字列構文、コメント構文、または 'その他のもの'と一致させます。
    • 「その他すべて」の部分で交換を行います。

    は、ここでの実装例です:

    $escapeSequence = "(?:\\\\[0'\"bnrtZ\\\\%_])"; 
    $singleQuoted = "'(?:[^'\\\\]|{$escapeSequence}|'')*'"; 
    $doubleQuoted = "\"(?:[^\"\\\\]|{$escapeSequence}|\"\")*\""; 
    $string   = "(?:{$singleQuoted}|{$doubleQuoted})"; 
    
    $lineEndComment = "(?:#[^\\r\\n]*|--\\s[^\\r\\n]*)"; 
    $multiLineComment = "(?:\/\\*(?:.|[\\r\\n])*?\\*\/)"; 
    $comment   = "(?:{$lineEndComment}|{$multiLineComment})"; 
    
    $pattern = "/({$string}|{$comment})/"; 
    
    $parts = preg_split($pattern, $query, -1, PREG_SPLIT_DELIM_CAPTURE); 
    for ($i=0, $n=count($parts)-1; $i<$n; $i+=2) { 
        $part = $parts[$i]; // non-string, non-comment part 
        // perform replacement of ? 
    } 
    $query = implode('', $parts); 
    

    パターンは完全ではないかもしれませんが、アイデアを得るために十分でなければなりません。

    関連する問題