2009-02-19 80 views
2

我正在查看一个字符串并试图获取一对括号内的所有内容。 内容可能会改变,最大值和最小值可能不会在某些情况下存在。在括号内获得文本的正则表达式

get(max(fieldname1),min(fieldname2),fieldname3)where(something=something) sort(fieldname2 asc) 

where()和sort()不保证在那里。
每组之间可能有空格,[EDIT]中的关键字可能并不总是相同的。

get(something) where(something) 
get(something)where(something) sort(something) 

应该使用哪种正则表达式模式? 实际上,它应该返回:

Array (
[0] => max(fieldname1),min(fieldname2),fieldname3 
[1] => something=something 
[2] => fieldname2 asc 
) 

我认识到,改变第一组括号中为{或[可以解决这个问题,但我很固执,并希望通过正则表达式来做到这样。

编辑 尽我所能想出了使用preg_match_all()

/[a-zA-Z0-9_]+\((.*?)\)/ 
+0

请发表您的当前最大的努力。 – Rob 2009-02-19 23:58:08

+0

外在的词总是得到,在哪里,并且排序,或者它们可以是任何东西?请澄清 – 2009-02-20 00:09:48

+0

可以是任何东西。基本上它只需要抓住两个外部支架之间的任何东西 - 编者 – atomicharri 2009-02-20 00:13:46

回答

1

既然你澄清,这些都是可选的,我不相信这将有可能使用正则表达式做。你可以通过将不同的子句(得到,在哪里排序)放在他们自己的字符串中来实现,但我认为你不能按现状来完成它。

再次编辑:这是概念上有点类似于从昨天这个问题,这被证明是不可能用正则表达式做: Regex for checking if a string has mismatched parentheses?

4

您更好地使用解析器如:

$str = 'get(max(fieldname1),min(fieldname2),fieldname3)where(something=something) sort(fieldname2 asc)'; 
$array = array(); 
$buffer = ''; 
$depth = 0; 
for ($i=0; $i<strlen($str); $i++) { 
    $buffer .= $str[$i]; 
    switch ($str[$i]) { 
     case '(': 
      $depth++; 
      break; 
     case ')': 
      $depth--; 
      if ($depth === 0) { 
       $array[] = $buffer; 
       $buffer = ''; 
      } 
      break; 
    } 
} 
var_dump($array); 
0

关于什么?

^\s*get\((.*?)\)(?:\s*where\((.*?)\))(?:\s*sort\((.*?)\)\s*)?$ 

现在我不相信这会奏效。例如,第一个匹配(for get)可能会溢出到where和sort子句中。您可能能够对付这种使用向前看符号,例如:

^\s*get\(((?:.(?!sort|where))*?)\)(?:\s*where\(((?:.(?!sort))*?)\))(?:\s*sort\((.*?)\)\s*)?$ 

但实际上这是一个非常粗糙的正则表达式和浓汤是正确的,一个分析器,可以说是更好的方式去。任何有匹配元素的情况都是如此。 HTML/XML是经常使用正则表达式的经典案例。在这些情况下更糟,因为解析器可以免费获得并且成熟。

有很多情况下在这样的处理:

  • 表达部分的可选性;
  • 来自文字的错误信号例如get(“)sort”)将打破上述;
  • 转义字符;
  • 嵌套。

乍得指出我正在谈论的匹配对问题,这是值得reitering。假设你有下面的HTML:

<div> 
    <div></div> 
</div> 

获取配对的标签是不可能的正则表达式(但人们不断尝试,或只是不占类型的输入)。是什么让你的情况可能可行是你有一些已知的标记,你可以使用:

  • 关键字得到的,在那里和排序;和
  • 字符串的开始和结束。

但老实说,正则表达式不是推荐的方法。

所以,如果你想要一些健壮和可靠的东西,写一个解析器。正则表达式对于这种事情不过是一个快速和肮脏的解决方案。

0

我支持关于正则表达式不适用于像这样的通用结构的说法。但是,只要括号是平衡的,不超过两个深,这些正则表达式可以帮助:

(\w+\s*\([^()]*(?:(?:\([^()]*\))[^()]*)*\)\s*) 

比赛和捕获单个XYZ(....)实例,而

(\w+\s*\([^()]*(?:(?:\([^()]*\))[^()]*)*\)\s*)+ 

比赛他们全部。根据您的语言,您可以使用第二个语言并分解单个组中的多个捕获。 This reference可能会有帮助。

但是,重复一遍,我不认为正则表达式就是这种方式 - 这就是为什么这个相当严格的解决方案如此尴尬。


对不起,刚才注意到你是PHP。你可能需要使用此:

(\w+\s*\([^()]*(?:(?:\([^()]*\))[^()]*)*\)\s*)(.*) 

你行上划分(单件)加(在休息)和环路周围,直到什么都不剩。

0

这是做的非常hackish的方式,也许可以做的更好,但正如概念证明:

get\((max\(.+?\)),(min\(.+?\)),(.+?)\)(where\((.+?=.+?)\)| where\((.+?=.+?)\)|)(sort\((.+?)\)| sort\((.+?)\)|) 

数据位置将在比赛阵列取决于信息是否被发现改变。 您可以测试出there

0

我坐了一会儿,写了一个完整的FSM解析器,只是为了感兴趣。 (至少在PHP下,我可以用Perl中的递归正则表达式来实现,但不是PHP,它没有这个功能)。但是,它有一些你不可能用正则表达式看到的特性。

  1. 智能和基于堆栈的托架解析
  2. AnyBracket支持
  3. 模块化
  4. 扩展。
  5. 当语法错误时,它可以告诉你在哪里。

当然,这里有一小部分代码,它对于新的编码器来说有点复杂和复杂,但是就它是什么而言,它是非常棒的东西。

它不是一个成品,只是有些我扔在一起,但它的工作原理,并没有任何我能找到的错误。

我已经在很多地方死了,通常情况下最好使用Exceptions和Nothingnot,所以清理和重构在推出之前更可取。

它有一个合理的评论量,但我觉得如果我进一步评论有限状态机加工的基本原理会更难理解。



# Pretty Colour Debug of the tokeniser in action. 
# Uncomment to use. 
function debug($title, $stream, $msg, $remaining){ 
# print chr(27) ."[31m$title" . chr(27) ."[0m\n"; 
# print chr(27) ."[33min:$stream" . chr(27) ."[0m\n"; 
# print chr(27) ."[32m$msg" . chr(27) ."[0m\n"; 
# print chr(27) ."[34mstream:$remaining" . chr(27) ."[0m\n\n"; 
} 

# Simple utility to store a captured part of the stream in one place 
# and the remainder somewhere else 
# Wraps most the regexy stuff 
# Insprired by some Perl Regex Parser I found. 

function get_token($regex, $input){ 
    $out = array( 
     'success' => false, 
     'match' => '', 
     'rest' => '' 
); 
    if(!preg_match('/^' . $regex . '/' , $input, $matches)){ 
    die("Could not match $regex at start of $input "); 
    #return $out; # error condition, not matched. 
    } 
    $out['match'] = $matches[1]; 
    $out['rest'] = substr($input, strlen($out['match'])); 
    $out['success'] = true; 
    debug('Scan For Token: '. $regex , $input, "matched: " . $out['match'] , $out['rest']); 
    return $out; 
} 


function skip_space($input){ 
    return get_token('(\s*)', $input); 
} 

# Given $input and $opener, find 
# the data stream that occurs until the respecive closer. 
# All nested bracket sets must be well balanced. 
# No 'escape code' implementation has been done (yet) 
# Match will contain the contents, 
# Rest will contain unprocessed part of the string 
# []{}() and bracket types are currently supported. 

function close_bracket($input , $opener){ 
    $out = array( 
     'success' => false, 
     'match' => '', 
     'rest' => '' 
); 

    $map = array('(' => ')', '[' => ']', '{' => '}', chr(60) => '>'); 
    $nests = array($map[$opener]); 

    while(strlen($input) > 0){ 
    $d = get_token('([^()\[\]{}' . chr(60). '>]*?[()\[\]{}' . chr(60) . '>])', $input); 
    $input = $d['rest']; 

    if(!$d['success']){ 
     debug('Scan For) Bailing ' , $input, "depth: $nests, matched: " . $out['match'] , $out['rest']); 

     $out['match'] .= $d['match']; 
     return $out; # error condition, not matched. brackets are imbalanced. 
    } 

# Work out which of the 4 bracket types we got, and 
# Which orientation it is, and then decide if were going up the tree or down it 

    end($nests); 
    $tail = substr($d['match'], -1, 1); 
    if($tail == current($nests)){ 
     array_pop($nests); 
    } elseif (array_key_exists($tail, $map)){ 
     array_push($nests, $map[$tail]); 
    } else { 
     die ("Error. Bad bracket Matching, unclosed/unbalanced/unmatching bracket sequence: " . $out['match'] . $d['match']); 
    } 
    $out['match'] .= $d['match'] ; 
    $out['rest' ] = $d['rest']; 
    debug('Scan For) running' , $input, "depth: $nests, matched: " . $out['match'] , $out['rest']); 

    if (count($nests) == 0){ 
     # Chomp off the tail bracket to just get the body 
     $out['match'] = substr($out['match'] , 0 , -1); 
     $out['success'] = true; 
     debug('Scan For) returning ' , $input, "matched: " . $out['match'] , $out['rest']); 
     return $out; 
    } 
    else { 

    } 
    } 
    die('Scan for closing) exhausted buffer while searching. Brackets Missmatched. Fix this: \'' . $out['match'] . '\''); 
} 

# Given $function_name and $input, expects the form fnname(data) 
# 'data' can be any well balanced bracket sequence 
# also, brackets used for functions in the stream can be any of your choice, 
# as long as you're consistent. fnname[foo] will work. 

function parse_function_body($input, $function_name){ 
    $out = array ( 
    'success' => false, 
    'match' => '', 
    'rest' => '', 
); 

    debug('Parsing ' . $function_name . "()", $input, "" , ""); 

    $d = get_token("(" . $function_name . '[({\[' . chr(60) . '])' , $input); 

    if (!$d['success']){ 
    die("Doom while parsing for function $function_name. Not Where its expected."); 
    } 

    $e = close_bracket($d['rest'] , substr($d['match'],-1,1)); 

    if (!$e['success']){ 
    die("Found Imbalanced Brackets while parsing for $function_name, last snapshot was '" . $e['match'] . "'"); 
    return $out; # inbalanced brackets for function 
    } 
    $out['success'] = true; 
    $out['match'] = $e['match']; 
    $out['rest'] = $e['rest']; 
    debug('Finished Parsing ' . $function_name . "()", $input, 'body:'. $out['match'] , $out['rest']); 

    return $out; 
} 

function parse_query($input){ 

    $eat = skip_space($input); 
    $get = parse_function_body($eat['rest'] , 'get'); 
    if (!$get['success']){ 
    die("Get Token Malformed/Missing, instead found '" . $eat['rest'] . "'"); 
    } 
    $eat = skip_space($get['rest']); 
    $where = parse_function_body($eat['rest'], 'where'); 
    if (!$where['success']){ 
    die("Where Token Malformed/Missing, instead found '" . $eat['rest'] . "'"); 
    } 
    $eat = skip_space($where['rest']); 
    $sort = parse_function_body($eat['rest'], 'sort'); 
    if(!$sort['success']){ 
    die("Sort Token Malformed/Missing, instead found '" . $eat['rest'] . "'"); 
    } 
    return array( 
     'get' => $get['match'], 
     'where' => $where['match'], 
     'sort' => $sort['match'], 
     '_Trailing_Data' => $sort['rest'], 
); 
} 



$structure = parse_query("get[max(fieldname1),min(fieldname2),fieldname3]where(something=something) sort(fieldname2 asc)"); 

print_r($structure); 

$structure = parse_query("get(max(fieldname1),min(fieldname2),fieldname3)where(something=something) sort(fieldname2 asc)"); 

print_r($structure); 

$structure = parse_query("get{max(fieldname1),min(fieldname2),fieldname3}where(something=something) sort(fieldname2 asc)"); 

print_r($structure); 

$structure = parse_query("get" . chr(60) . "max(fieldname1),min(fieldname2),fieldname3" . chr(60). "where(something=something) sort(fieldname2 asc)"); 

print_r($structure); 

上述所有的print_r($结构)的线应该产生这样的:

 
Array 
(
    [get] => max(fieldname1),min(fieldname2),fieldname3 
    [where] => something=something 
    [sort] => fieldname2 asc 
    [_Trailing_Data] => 
) 
相关问题