1

文字列内に何かを抽出しようとしています。私は次の文字列を手に入れました:

*, bob, DATE('gdfgfd', 'Fdsfds', ('fdsfdfsd')), george

()の外側にコンマで抽出したいのですが、これを与えると仮定します:

  • *
  • ボブ
  • DATE('gdfgfd'、'Fdsfds'、('fdsfdfsd'))
  • ジョージ

私はexplodeを使おうとしていますが、関数meanによるロジック(および)...の内部でもカットされます。

だから私はこれをしました:[^(,\s]+|\([^)]+\)しかし、括弧の中にコンマが見つかったとしても、それはカットを与えます。

誰もが私が意味することを行う方法を知っていますか?

ありがとう

編集 :

非常に明確で直接的であることを確認してください。

私はこれを得た :SELECT MyField, Field2, Blabla, Function(param), etc FROM table Blabla

MyField, Field2, Blabla, Function(param), etcクエリは次のような複数の関数クラスによって実行されるため、すでに文字列を取得していますが$DB->Select('MyField, Field2, Blabla, Function(param), etc');、コンマの間のすべてを解析したいので、次のようMyField, Field2, Blabla, Function(param), etcになります。

  • MyField
  • フィールド2
  • ブラブラ
  • 関数(パラメータ)
4

6 に答える 6

4

おそらく他の何よりも優れているので、これを回答として投稿します。

http://code.google.com/p/php-sql-parser/

そのプロジェクトを使用してSQLステートメントを解析します。SELECT結果は、必要に応じて、中間のビットと個々の要素を含む配列FROMとして返されます。これは、使用する正規表現ソリューションよりもはるかにうまく機能します。

于 2012-05-25T15:50:48.843 に答える
2

これが私が作り上げたもので、マルチバイト文字をサポートしていません:

編集:文字列認識を追加

<?php


$stack = array();
$stuff = array();

$escaping = false;
$input = "*, bob, [], DATE('g()d\\'f,gfd', ('Fd()sf)ds'), ('fdsfd\"\"()fsd')), ',(),() (,,'";
$len = strlen( $input );
$i = 0;
$curstr = "";
$char;

while( $i < $len ) {
    $char = $input[$i++];

    if( $escaping ) {
        $curstr .= $char;
        $escaping = false;
        continue;
    }

    switch( $char ) {

        case "\\":
            $escaping = true;
            break;

        case '"':
            $top = end( $stack );
            if( $top === '"' ) {
                array_pop( $stack );
            }
            else if( $top !== "'" ){
                $stack[] = '"';
            }

            $curstr .= $char;
            break;

        case "'":
            $top = end( $stack );
            if( $top === "'" ) {
                array_pop( $stack );
            }
            else if( $top !== '"' ) {
                $stack[] = "'";
            }

            $curstr .= $char;           
            break;

        case ",":
            if( count( $stack ) ) {
                $curstr .= $char;
            }
            else {
                $stuff[] = trim($curstr);
                $curstr = "";
            }
            break;

        case "(":
            $top = end( $stack );
            if( $top !== "'" && $top !== '"' ) {
                $stack[] = "(";                   
            }

            $curstr .= $char;
            break;

        case ")":
            $top = end( $stack );

            if( $top !== "'" && $top !== '"' ) {
                if( end($stack) !== "(" ) {
                    die( "Unbalanced parentheses" );
                }
                array_pop( $stack );
            }

            $curstr .= $char;


            break;

        default:
            $curstr .= $char;
            break;

    }
}

if( count( $stack ) ) {
    die( "Unbalanced ".end($stack) );
}

$stuff[] = trim( $curstr );

print_r( $stuff );

/*
    Array
(
    [0] => *
    [1] => bob
    [2] => []
    [3] => DATE('g()d'f,gfd', ('Fd()sf)ds'), ('fdsfd""()fsd'))
    [4] => ',(),() (,,'
)

*/
于 2012-05-25T15:55:08.933 に答える
0

ネストされたリストがあるため、再帰を使用する準備ができているとコメントで述べました。ただし、正規表現は再帰を実行できません。これは、正規表現が何も無期限に「カウント」できないためです。開き/閉じ括弧を数える方法がないので、それがいくつのレベルであるか、またはそれがいくつのレベルを出なければならないかを知ることができません。

Nレベルの深さを処理するために恐ろしく複雑な正規表現を書くことができます(anubhavaの答えを参照)が、N + 1レベルの深さの式に出くわすとすぐに、正規表現は失敗します。これが、再帰をカウントできるため、プログラミング言語を使用して不規則な言語を解析する理由です(diolemoの回答を参照)。この再帰の中で、正規表現の小さなビットを使用できます。

于 2012-05-25T15:31:15.483 に答える
0

これは(ほとんどの場合)機能します。引用符(データの一部)内に角かっこがある場合は失敗します。必要に応じて、引用符で囲まれた角かっこを処理するようにコードを拡張できます(ただし、エスケープされた引用符などを考慮する必要があります。正規表現はうまく機能しません。

編集:SpikeXの回答に従ってPHPSQLパーサーを使用することをお勧めします。

function unreliable_comma_explode($str)
{
   $last_split = 0;
   $len = strlen($str);
   $brackets = 0;
   $parts = array();

   for ($i = 0; $i < $len; $i++)
   {
      if ($str[$i] == '(') 
      {
         $brackets++;
         continue;
      }

      if ($str[$i] == ')')
      {
         if (--$brackets == -1) $brackets = 0;
         continue;
      }

      if ($str[$i] == ',' && $brackets == 0)
      {
         $parts[] = substr($str, $last_split, ($i-$last_split));
         $last_split = $i + 1;
      }
   }

   if (($len-$last_split) > 0)
      $parts[] = substr($str, $last_split, ($len-$last_split));

   return $parts;
}
于 2012-05-25T15:45:30.183 に答える
0

この正規表現ベースのコードを使用して、分割結果を希望どおりに取得できます。

$str = "*, bob, DATE('gdfgfd', 'Fdsfds', ('fdsfdfsd')), george";
$arr = preg_split('/([^,]*(?:\([^)]*\))[^,]*)+|,/', $str, -1,
                      PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

アップデート:

私の元の答えはOPが投稿した例では機能しましたが、一部のメンバーからの懸念により、括弧のバランスが取れている限り、ネストされた括弧で機能するソリューションを投稿しています。

$str = "*, bob, DATE('gdfgfd', ('Fdsfds'), ('fdsfdfsd', ('foo'))) 'foo'=[bar]," .
       "john, MY('gdfgfd', ((('Fdsfds'))), ('fdsfdfsd')), george";
$arr = preg_split('/\s*( [^,()]* \( ( [^()]* | (?R) )* \) [^,()]* ) ,?\s* | \s*,\s*/x',
                  $str, -1 , PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
print_r($arr);

出力:

Array
(
    [0] => *
    [1] => bob
    [2] => DATE('gdfgfd', ('Fdsfds'), ('fdsfdfsd', ('foo'))) 'foo'=[bar]
    [3] => john
    [4] => MY('gdfgfd', ((('Fdsfds'))), ('fdsfdfsd'))
    [5] => george
)

注意:この再帰ベースの正規表現パターンは、ネストされた深い角かっこで機能しますが、一部のエッジケースの状況(角かっこが不均衡など)でこれを破ることができないという意味ではありません。

于 2012-05-25T15:47:31.450 に答える
-1

ここで何をしたいのかよくわかりませんが、文字列を抽出したいだけの場合は。implodeを使用できます。

$array = array("*", "bob", "DATE('gdfgfd', 'Fdsfds', '(\"fdsfdfsd\"))", "george");
echo $test = implode($array, ",");
于 2012-05-25T15:39:30.097 に答える