Utilisez PCRE modèle récursif pour faire correspondre des sous-chaînes dans des parenthèses imbriquées :
$str = "a(bc)de(fg)h some text a(bcd(ef)g)h ";
preg_match_all("/\((((?>[^()]+)|(?R))*)\)/", $str, $m);
print_r($m[1]);
La sortie :
Array
(
[0] => bc
[1] => fg
[2] => bcd(ef)g
)
\( ( (?>[^()]+) | (?R) )* \)
D'abord, il fait correspondre une parenthèse ouvrante. Ensuite, il correspond à un nombre quelconque de sous-chaînes qui peuvent être soit une séquence de caractères non parenthèses, soit une correspondance récursive avec le modèle lui-même (c'est-à-dire une sous-chaîne correctement parenthésée). Enfin, il y a une parenthèse fermante.
Précautions techniques:
S'il y a plus de 15 parenthèses capturantes dans un modèle, PCRE doit obtenir de la mémoire supplémentaire pour stocker des données pendant une récursion, ce qu'il fait en utilisant pcre_malloc, en le libérant via pcre_free par la suite. Si aucune mémoire ne peut être obtenue, il ne sauvegarde des données que pour les 15 premières parenthèses capturantes, car il n'y a pas de moyen de générer une erreur de mémoire insuffisante à partir d'une récursion.