Précédent   Forum des professionnels en informatique > PHP > Langage > Regex
Regex Forum d'entraide sur les expressions rationnelles PHP. Avant de poster -> FAQ regex, Cours de regex et Sources de regex
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 15/04/2007, 11h29   #1
Membre à l'essai
 
Inscription : janvier 2005
Messages : 88
Détails du profil
Informations forums :
Inscription : janvier 2005
Messages : 88
Points : 22
Points : 22
Par défaut Problème de balises /paranthèses imbriquée

Bonjour à tous! Je vais illustrer mon problème par un exemple (avec des parethèses, mais ça pourrai aussi être des balises).

Texte: 6*(1+(4-2)/(sin(x)+(4+7)))-9*(2^(3-2)+1)
But: Rechercher les groupes de paranthèse:
c'est-à-dire qu'il me donne:
1+(4-2)/(sin(x)+(4+7)) et 2^(3-2)+1
C'est à dire que dès qu'il voit l'ouverture d'une paranthèse il va chercher celle qui se ferme (et qui lui corresond) et retourne le contenu.

Il y a-t-il un moyen de faire ça avec des regexp ou le mieux et de programmer le truc sans regexp?

Merci d'avance!

PS: Si je suis pas clair, n'hésitez pas à me le faire savoir...
bugmenot est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/04/2007, 01h35   #2
Membre habitué
 
Avatar de daniel61
 
Inscription : décembre 2006
Messages : 109
Détails du profil
Informations forums :
Inscription : décembre 2006
Messages : 109
Points : 120
Points : 120
Citation:
Envoyé par bugmenot
Texte: 6*(1+(4-2)/(sin(x)+(4+7)))-9*(2^(3-2)+1)
But: Rechercher les groupes de paranthèse:
c'est-à-dire qu'il me donne:
1+(4-2)/(sin(x)+(4+7)) et 2^(3-2)+1
C'est à dire que dès qu'il voit l'ouverture d'une paranthèse il va chercher celle qui se ferme (et qui lui corresond) et retourne le contenu.
de mémoire, il y a un exemple sur php.net comme sur pcre.org dans la partie "recursive patterns", masques récursifs en français. moi j'écrirais preg_match_all('#[(]((?:[^()]+|(?R))*)[)]#',....); pas du tout testé.

bon, j'ai l'impression de t'apporter + de questions que de réponses... si tu as des questions supplémentaires, n'hésites pas, mes neurones déficiantes arriveront peut-être à formuler quelque chose d'intelligent.

ouais, aussi bien trouver la page sur php.net...
http://www.php.net/manual/fr/referen...ern.syntax.php
vers le bas sous "masques récursifs" tu as des explications et la regex est bien là '#\( ( (?>[^()]+) | (?R) )* \)#x' et elle a une drôle de tête... pour capturer en \\1 sans la première parenthèse ouvrante et la dernière parenthèse fermante, tu peux la transformer en '#\( ( (?: (?>[^()]+) | (?R) )* ) \)#x' et elle a toujours une drôle de tête, m'enfin ça vient de la doc officielle.

l'option x permet d'ajouter des espaces pour aérer l'expression, mais en même temps elle enlève la possibilité d'utiliser l'espace comme pattern... et c'est souvant pratique l'espace, dans du html notamment.

(?>...) est un masque unique, un genre d'ancrage dans le vide, dans ce cas si (?>[^()]+) ne sortira pas du masque unique tant et aussi longtemps qu'il n'y aura pas de caractère ( ou ) de rencontré dans la chaine source. en théorie c'est supposé accélérer les temps de traitement, dans la pratique mes tests m'ont plutôt donner de sévève ralentissements.

|(?R) est la récursive, qui répétera du pattern précédent (?>...) jusqu'à ce qui succède (?R). toutes les formes récursives doivent en fait être vues comme des sous-routines. ici la particularité de |(?R) est d'être un genre de do-while... et le do-while ce fait de \( à \)...

des questions?
daniel61 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/04/2007, 11h50   #3
En attente de confirmation mail
 
Inscription : juin 2002
Messages : 6 164
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 6 164
Points : 6 404
Points : 6 404
Pour l'idée de faire sans voilà ce que je vous propose :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$texte = "6*(1+(4-2)/(sin(x)+(4+7)))-9*(2^(3-2)+1)";
 
function smart_split($texte) {
    $parentheses = array();
    $pile = array();
    $nb = 0;
    for ($i = 0, $l = strlen($texte); $i < $l; $i++) {
        if ($texte[$i] == '(') {
            array_push($pile, $nb++);
            $parentheses[] = array($i);
        } else if ($texte[$i] == ')') {
            $parentheses[array_pop($pile)][1] = $i;
        }
    }
    return $parentheses;
}
 
foreach (smart_split($texte) as $partie) {
    echo substr($texte, $partie[0] + 1, $partie[1] - $partie[0] - 1) . '<br/>';
}
Le tableau renvoyé par smart_split étant de la forme :
Code X :
1
2
3
4
5
6
7
8
9
10
11
Array (
  0 => Array ( // Première parenthèse trouvée
    0 => position de la parenthèse ouvrante
    1 => position de la parenthèse fermante
  ),
  1 => Array ( // Deuxième parenthèse trouvée
    0 => position de la parenthèse ouvrante
    1 => position de la parenthèse fermante
  ),
 // ...
)
Résultat obtenu avec 6*(1+(4-2)/(sin(x)+(4+7)))-9*(2^(3-2)+1) :
Citation:
1+(4-2)/(sin(x)+(4+7))
4-2
sin(x)+(4+7)
x
4+7
2^(3-2)+1
3-2
julp est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/04/2007, 18h54   #4
Membre à l'essai
 
Inscription : janvier 2005
Messages : 88
Détails du profil
Informations forums :
Inscription : janvier 2005
Messages : 88
Points : 22
Points : 22
merci pour a solution Regexp. C'est exactement ce que je cherchais (j'ai pas encre testé, mais ça devrait fonctionner au poil).

EDIT: Bon je viens de tester et ça marche pas sous Python

voila le code python (pour d'autre eventuelles interessé):

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
class MaskError(Exception):
         def __init__(self, value):
             self.value = value
         def __str__(self):
             return repr(self.value)
 
def get_par(txt,delim=("(",")")):
    res=[]
    deb=-1
    k=0
    for x in enumerate(txt):
        if x[1]==delim[0]:
            k+=1
            if deb==-1: deb=x[0]
        if x[1]==delim[1]:
            k-=1
            if k<0 or deb==-1: raise MaskError, "too many closing delimiter"
            elif k==0:
                res.append(txt[deb+1:x[0]])
                deb=-1
    if k>0: raise MaskError, "too many opening delimiter"
    return res
bugmenot est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/04/2007, 03h10   #5
Membre habitué
 
Avatar de daniel61
 
Inscription : décembre 2006
Messages : 109
Détails du profil
Informations forums :
Inscription : décembre 2006
Messages : 109
Points : 120
Points : 120
Citation:
Envoyé par bugmenot
EDIT: Bon je viens de tester et ça marche pas sous Python
les expressions régulières sous python ne supportent pas les récursives, par contre php supporte très bien les récursives et il y a d'autres différences entre python et php. ça aurait été gentil d'avoir dit que c'était pour python avant maintenant. dans le doute, j'ai testé les 3 expressions de mon message précédent sous plusieurs versions php sur différentes machines, et elles sont toutes les 3 fonctionnelles sous php... il aurait-été navrant qu'une expression sur le site même de pcre.org comme sur le site de php.net ne soit pas fonctionnelle.
daniel61 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/04/2007, 09h24   #6
Membre chevronné
 
Avatar de Korko Fain
 
Étudiant
Inscription : août 2005
Messages : 632
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : août 2005
Messages : 632
Points : 632
Points : 632
Ne cherche pas à le faire en 1 expression régulière, ce n'est pas possible. Il te faut une fonction (Il te faudrait une Pile pour le faire simplement donc un simple tableau suffit)
Korko Fain est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/04/2007, 21h08   #7
Membre à l'essai
 
Inscription : janvier 2005
Messages : 88
Détails du profil
Informations forums :
Inscription : janvier 2005
Messages : 88
Points : 22
Points : 22
ben une regexp reste une regexp, donc préciser que c'était pour python n'aurait pas changer grand chose (mais je m'aprecois du contraire...). De plus je fais aussi du php et cette fonction m'intressait de toute façon. Donc ton tuyau n'a pas été si inutile que ça; merci d'ailleur pour le tuyau.

Citation:
Ne cherche pas à le faire en 1 expression régulière, ce n'est pas possible. Il te faut une fonction (Il te faudrait une Pile pour le faire simplement donc un simple tableau suffit)
C'est gentil de voiloir aider, mais tu m'expliques l'utilité de ton message? On vient de dire plus haut que les regexp récursives ne fonctionnent pas sous python et en plus j'ai posté le prog pour le faire en non-regexp....
bugmenot est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 02h40.


 
 
 
 
Partenaires

Hébergement Web