2013-02-04 177 views
1

給定一個字符串,匹配在第一次出現單詞後出現的所有內容。這個詞不能出現在一對括號內的任何地方,但也可以是其他詞。例如:正則表達式不在括號內

SELECT 
t1.col1, 
(SELECT t2.col1 FROM table2 t2 
    WHERE t2.id IN(SELECT * FROM table5 WHERE id = t2.id) 
) AS alias1, 
t1.col2 
---------- 
FROM 
table1 t1, 
(SELECT id FROM table3 t3 WHERE t3.id = t1.table3_id) t3, 
table4 t4 

我正在尋找一切虛線AFTER - 具體而言,一切字FROM一號外觀不隨地一對括號

內如果贏了的正則表達式後出現」不,我會製作一個PHP語句來解析。我也很難過,那麼!我想要做到這一點,我將不得不用字符和括號來標記字符串?

+0

不能用正則表達式來處理一般情況;那些無法計數,因此不能告訴你在一個開放括號之後它又被關閉了。儘管如此,我不知道sql是否支持正則表達式的擴展。 –

+0

我會考慮製作一個PHP函數,在這方面也有難度! – rmirabelle

+1

你可以這樣做:從第一個字母開始掃描FROM的字符串。爲嵌套深度保留一個計數器,初始化爲0.每當一個支架打開時,增加它;當括號關閉時,減少它(減1)。每當計數器!= 0時,只需掃描字符,直到計數器爲0而不檢查FROM。一旦你有第一次出現FROM,從那裏開始的子字符串。 –

回答

1

我認爲,正則表達式可能不是最好的解決方案在這裏,因爲他們可以非常困難的(或不可能)時,嵌套的括號都參與其中。

我也認爲遍歷每個字符並不是最好的方法,因爲它會導致大量不必要的循環。

我覺得這是最好的辦法:

查找指定字符串的每次出現,並且一次出現之前數括號的數量。如果開局參數的數量等於結束參數的數量,那麼你有正確的匹配。這樣做會減少循環,你只是檢查你真正想要檢查的內容。

我做了一個功能findWord採取這種方法。它適用於您的示例,其中$in是您的SQL語句,而$search'FROM'

function findWord($in, $search) { 

    if(strpos($in, $search) === 0) return $in; 

    $before = ''; 
    while(strpos($in, $search, 1)) { 
     $i = strpos($in, $search, 1); 
     $before .= substr($in, 0, $i); 
     $in = substr($in, $i); 

     $count = count_chars($before); 

     if($count[40] == $count[41]) 
      return $in; 
    } 

    return false; 
} 
+0

我會給這個方法一個測試。我喜歡針對特定$搜索的概念,但它似乎以犧牲透明度爲代價。最終,由於平均SQL語句長度,性能應該不成問題。感謝您的意見。 – rmirabelle

+0

@rmirabelle如果你喜歡這個概念,那麼upvote怎麼樣? ;)無論如何,我會在今天晚些時候通過並添加一些評論,以更好地解釋函數。 –

+0

upvote賺了 - 測試和工作 - 性能約爲我的腳本在中等大小SQL塊上的兩倍。雖然兩者都可以忽略不計:.0001與.0002 – rmirabelle

0

我打算採用編程方法,除非有人有更好的答案。

/** 
* Find the portion of the SQL statement occurring after 
* the first occurrence of the word 'FROM' (which itself 
* does not appear within parens) 
*/ 
public static function sql_after_from($sql) { 
    $arr = str_split($sql); 
    $indent = 0; 
    $out = ''; 
    $start = 0; 
    $len = count($arr); 
    for($x=0; $x < $len; $x++) { 
     $c = $arr[$x]; //current character 
     if($c == '(') $indent++; 
     if($c == ')') $indent--; 
     $out .= $arr[$x]; 
     //do the last 4 letters spell FROM? 
     if(substr($out, $x-3, $x) == 'FROM') { 
      if($indent == 0) { //not anywhere within parens 
       $start = $x+2; 
       break; //go no further 
      } 
     } 
    } 
    //everything after the first occurrence of FROM 
    return substr($sql, $start); 
}