2009-02-19 87 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] => 
) 
相關問題