2010-10-11 3 views
3

Je sais que cette question a été posée à plusieurs reprises, mais je ne trouve pas de solution de travail pour mon cas. Je souhaite diviser une chaîne dans PHP (5.3) en utilisant des points-virgules comme délimiteurs, sauf s'ils sont compris entre $BODY$. L'objectif est de diviser les instructions SQL où les instructions peuvent être des procédures (postgresql dans ce cas).Chaîne fractionnée sauf si elle est entourée d'autres chaînes

Exemple:

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

devrait se traduire par:

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

Je suis en train de jouer avec preg_split pendant un certain temps et ne peut pas trouver une solution de travail.

Un grand merci

Edit: il doit fonctionne avec des entrées multilignes (mais je peux supprimer les sauts de ligne à l'aide str_replace avant la main)

+0

Donnez une * plus simple * exemple, plus entrée textuelle et le résultat de la production attendue. Sinon, les gens recommanderont d'écrire un analyseur. – mario

+0

fait, merci pour votre commentaire – maximebf

Répondre

0

Comme aucun regexps semblaient correspondre, voici comment je l'ai fait pour celui qui sont intéressés:

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

Cela fonctionnerait en supposant qu'il y avait était pas plusieurs niveaux de emboîtée $ BODY $. Je pense qu'il doit y avoir une expression régulière qui pourrait accomplir mais mon cerveau ne coopère pas pour le moment.

0

Voici un modèle rapide qui correspond à votre exemple. Espérons que cela va vous diriger dans la bonne direction pour quelque chose de plus souple:

$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

J'ai oublié de mentionner qu'il y a du texte devant la balise $ BODY $ qui casse l'expression rationnelle. J'ai mis à jour l'exemple. Merci quand même! – maximebf

0

ici est un moyen plus simple.

$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

Votre propre solution ne fonctionne pas avec l'exemple fourni. La sortie que je reçois est:

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

Un changement mineur dans l'expression rationnelle de Nev Stokes fait fonctionner selon les besoins:

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