正则表达式不在括号内

问题描述:

给定一个字符串,匹配在第一次出现单词后出现的所有内容。这个词不能出现在一对括号内的任何地方,但也可以是其他词。例如:正则表达式不在括号内

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,从那里开始的子字符串。 –

我认为,正则表达式可能不是最好的解决方案在这里,因为他们可以非常困难的(或不可能)时,嵌套的括号都参与其中。

我也认为遍历每个字符并不是最好的方法,因为它会导致大量不必要的循环。

我觉得这是最好的办法:

查找指定字符串的每次出现,并且一次出现之前数括号的数量。如果开局参数的数量等于结束参数的数量,那么你有正确的匹配。这样做会减少循环,你只是检查你真正想要检查的内容。

我做了一个功能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

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

/** 
* 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); 
}