1

我一直在尝试在字符串中提取一些东西。我得到了以下字符串:

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

我想在 () 之外用逗号提取,它应该是这样的:

  • *
  • 鲍勃
  • 日期('gdfgfd','Fdsfds',('fdsfdfsd'))
  • 乔治

我一直在尝试使用explode,但它甚至在函数内部(和)......逻辑中被函数的意思。

所以我这样做了:[^(,\s]+|\([^)]+\)但即使在括号内找到逗号,它也会给cut。

任何人都知道该怎么做我的意思?

谢谢

编辑 :

好的,非常清楚和直接。

我懂了 :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变成这样:

  • 我的领域
  • 字段2
  • 布拉布拉
  • 函数(参数)
  • ETC
4

6 回答 6

4

将此作为答案发布,因为它可能比其他任何东西都好:

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

使用该项目来解析您的 SQL 语句。结果以数组的形式返回,包括中间的位SELECTFROM单独的元素,就像你想要的那样。这将比您使用的任何正则表达式解决方案好得多。

于 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

您可以使用此基于正则表达式的代码以您想要的方式获取拆分结果:

$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 回答
0

您在评论中声明您准备使用递归,因为您有嵌套列表。但是,正则表达式不能进行递归。这是因为正则表达式不能无限期地“计算”任何东西。由于它无法计算开/关括号,它无法知道其中有多少层,或者它必须去多少层。

您可以编写极其复​​杂的正则表达式来处理 N 级深度(请参阅anubhava 的答案),但是一旦您遇到具有 N+1 级深度的表达式,您的正则表达式就会失败。这就是为什么我们使用编程语言来解析不规则语言的原因,因为它们可以计算递归(参见diolemo 的回答)。这个递归中,我们可以使用少量的正则表达式。

于 2012-05-25T15:31:15.483 回答
0

这将起作用(在大多数情况下)。如果引号内有括号(数据的一部分),它将失败。如果你愿意,你可以扩展代码来处理带引号的括号(但是你必须考虑转义引号和类似的东西。正则表达式永远不会很好用。

编辑:最好使用 SpikeX 回答的 PHP SQL Parser。

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 回答
-1

我不太确定你想在这里做什么。但如果你只是想提取字符串。你可以只使用内爆。

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