【问题标题】:Regex for word not between parentheses不在括号之间的单词的正则表达式
【发布时间】:2013-01-18 18:18:01
【问题描述】:

给定一个字符串,匹配单词第一次出现之后出现的所有内容。该单词不得出现在一对括号内的任何位置,但其他单词可以。例如:

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

我正在寻找虚线之后的所有内容 - 特别是在单词 FROM 第一次出现之后的所有内容,它没有出现在一对括号内的任何地方

如果 Regex 不行,我会制作一个 PHP 语句来解析。我也很难过,寿!我想这样做,我必须按单词和括号对字符串进行标记?

【问题讨论】:

  • 不能用正则表达式处理一般情况;那些无法计数,因此无法告诉您在打开括号后它在什么时候再次关闭。不过,我不知道 sql 是否支持对允许这样做的正则表达式的扩展。
  • 我会考虑制作一个 PHP 函数,但也很难做到!
  • 您可以这样做:从第一个字母开始扫描字符串以查找 FROM。为嵌套深度保留一个计数器,初始化为 0。每当括号打开时,增加它;当括号关闭时,将其减小(减 1)。每当计数器!= 0 时,只需扫描字符直到计数器为 0,而不检查 FROM。一旦你第一次出现 FROM,就从那里开始获取子字符串。
  • 您的建议看起来不错 - 无法弄清楚如何做到这一点;-)

标签: php sql regex


【解决方案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;
}

【讨论】:

  • 我来测试一下这个方法。我喜欢针对特定 $search 的概念,但它肯定似乎是以牺牲清晰度为代价的。最终,由于 SQL 语句的平均长度,性能应该不是问题。感谢您的意见。
  • @rmirabelle 如果您喜欢这个概念,请点赞如何? ;) 无论如何,我将在今天晚些时候通过并添加一些评论以更好地解释该功能。
  • upvote 赢得 - 经过测试和工作 - 在中等大小的 SQL 块上,性能大约是我下面脚本的 2 倍。尽管两者都可以忽略不计:.0001 vs .0002
  • 我对 strpos 调用中 1 的偏移量感到特别困惑。
  • 偏移量是第一个循环之后的循环。由于我们从$in 的开头一直到每次出现$search,所以$in 在第一个循环之后总是以$search 开头。如果没有偏移,strpos 将始终匹配第一个字符。
【解决方案2】:

除非有人有更好的答案,否则我将采用程序化方法。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-03
    • 2015-08-13
    • 1970-01-01
    • 2018-03-24
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 2020-10-18
    相关资源
    最近更新 更多