正则表达式提取

时间:2012-05-25 15:16:53

标签: php regex

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

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

我想在()之外用逗号提取,并且假设给出:

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

我一直在尝试使用爆炸,但它通过函数均值来削减内部(和)...逻辑。

所以我已经这样做了:[^(,\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成为:{/ p>

  • MyField的
  • 字段2
  • BLABLA
  • 功能(PARAM)

6 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分: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] => ',(),() (,,'
)

*/

答案 2 :(得分:0)

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

你可以编写非常复杂的正则表达式来处理N级深度(参见anubhava's answer),但是一旦你遇到N + 1级深度的表达式,你的正则表达式就会失败。这就是我们使用编程语言来解析不规则语言的原因,因为它们可以计算递归(参见diolemo's answer)。 这个递归中,我们可以使用一小部分正则表达式。

答案 3 :(得分: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;
}

答案 4 :(得分:0)

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

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

更新

虽然我的原始答案适用于OP发布的示例,但由于某些成员提出的问题,我发布的解决方案将使用嵌套括号以及只要括号平衡: < / p>

$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
)

警告:尽管这种基于递归的正则表达式模式适用于深嵌套括号,但这并不意味着在某些边缘情况下(例如不平衡括号)不会破坏它。

答案 5 :(得分:-1)

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

$array = array("*", "bob", "DATE('gdfgfd', 'Fdsfds', '(\"fdsfdfsd\"))", "george");
echo $test = implode($array, ",");