Separate a line if it is not between other lines

I know that this question has been asked endless times, but I can’t find a working solution for my case.

I want to split a string in PHP (5.3), using semicolons as separators if they are not between the lines $BODY$. The goal is to break up SQL statements where statements can be procedures (postgresql in this case).

Example:

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

It should turn out:

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

I played with for a while preg_splitand did not find a working solution.

Many thanks

Edit: it should work with multi-line inputs (but I can remove line breaks using str_replacebefore starting)

+3
source share
5 answers

Since no regular expressions seemed to fit, here's how I did it for someone who is interested:

$ 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);
0
source
$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 $. , , , .

0

Here is a quick template that will suit your example. Hopefully he will point you in the right direction for something more flexible:

$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);
0
source

here's an easier way.

$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);
0
source

Your own solution does not work with the given example. The output I get is:

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

A slight change in the regular expression of Nev Stokes makes it work as needed:

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

Source: https://habr.com/ru/post/1768974/


All Articles