除非包含在其他字符串之间

时间:2010-10-11 12:48:23

标签: php sql

我知道这个问题已被无数次询问,但我无法找到适合我案例的解决方案。

我希望使用分号作为分隔符在PHP(5.3)中拆分字符串,除非它们位于$BODY$个字符串之间。目标是拆分SQL语句,其中语句可以是过程(在本例中为postgresql)。

示例:

select; start $BODY$ begin; end; $BODY$ lang; update

应该导致:

select
start $BODY$ begin; end; $BODY$ lang
update

我一直在玩preg_split一段时间,找不到合适的解决方案。

非常感谢

编辑:它必须适用于多行输入(但我可以先使用str_replace删除换行符)

5 个答案:

答案 0 :(得分:0)

$a = explode(';', 'select; $BODY$ begin; end; $BODY$ lang; update');
$b = array();
$index = 0;
$waiting = false;
foreach($a as $str) {
    if(strpos($str,'$BODY$') !== false) {
        $waiting = !$waiting;
    }
    $b[$index] .= $str.';';
    if(!$waiting) {
        $index++;
    }
}
print_r($b);

这可以假设没有多个级别的嵌套$ BODY $。我觉得必须有一个可以完成的正则表达,但我的大脑目前还没有合作。

答案 1 :(得分:0)

这是一个与你的例子相符的快速模式。希望它能为您提供更灵活的方向:

$string = 'select; $BODY$ begin; end; $BODY$ lang; update';

preg_match('/^(?:(.*?);\s?)?(\$BODY\$.+?\$BODY\$[^;]+)(?:;\s?(.+?))?$/', $string, $array);
$array = array_filter($array);
$array = array_slice($array, 1, 3);

var_dump($array);

答案 2 :(得分:0)

由于似乎没有正则表达式,所以我是如何为感兴趣的人做的:

$length = strlen($sql);
$queries = array();
$offset = 0;
$last = 0;
do {
    if (($colon = strpos(substr($sql, $offset), ';')) === false) {
        break;
    }
    $colon += $offset;

    if (($body = strpos(substr($sql, $offset), '$BODY$')) !== false) {
        $body += $offset;
        if ($body < $colon) {
            $offset = $body + strpos(substr($sql, $body + 6), '$BODY$') + 12;
            continue;
        }
    }

    $queries[] = trim(substr($sql, $last, $colon - $last));
    $last = $offset = $colon + 1;

} while($offset <= $length);

答案 3 :(得分:0)

这是一种更简单的方法。

$test_string = 'select; start $BODY$ begin; end; $BODY$ lang; update';

$test_string = explode('$BODY$', $test_string);
$level_flag = 1;
for ($i = 0; $i < count($test_string); $i++) {
    if ($level_flag) {
        $test_string[$i] = str_replace(';', "\n", $test_string[$i]);
        $level_flag = 0;
    } else {
        $level_flag = 1;
    }
}
$test_string = implode('$BODY$', $test_string);

答案 4 :(得分:0)

您自己的解决方案不适用于提供的示例。我得到的输出是:

select
start $BODY$ begin; end; $BODY$ lang

Nev Stokes的regexp的微小变化使其按要求工作:

$sql = 'select; start $BODY$ begin; end; $BODY$ lang; update';
preg_match(
    '/^(?:(.*?);\s?)([^;]+\$BODY\$.+?\$BODY\$[^;]+)(?:;\s?(.+?))$/',
    $sql,
    $queries
);
array_shift($queries);