Page 1 sur 2

Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:01
par hickscorp
Hello :)

Je précise avant de commencer: je ne pose pas du tout une question sur SQL ou MySQL. Ma question est à dissocier totallement des fonctionnalités MySQL.

Je dispose au moment de l'execution de mon programme d'une chaine de caractère contenant des condition SQL.
Je souhaite extraire la totalité des tables présentes dans cette chaine.

Quelques exemples de ces chaines: "Tatas.b=1"
ou encore: "Totos.a IN (1) AND Titis.c IN (1)"
Ou même: "COUNT(Tatas.d) > 3 AND Trotros.e LIKE '%Ha%'"
Je précise pour cette dernière chaine que je ne parle donc pas que de conditions "WHERE", mais aussi "HAVING"...

Pour l'instant, je pense utiliser preg_split avec une condition établie sur la base de:
- N'est pas entre guillemets simples ou doubles.
- Commence par une majuscule.
- Finit par un "s" puis un point.

Est-ce que quelqu'un aurait une solution établie déja faite, ou dois-je me lancer dans l'élaboration du Regexp au risque d'oublier les exceptions?

Merci :)
Pierrot.

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:05
par stealth35
suivant ta description ca donnerai : (?<!')[A-Z]\w+s\.

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:17
par hickscorp
suivant ta description ca donnerai : (?<!')[A-Z]\w+s\.
Génial. Merci beaucoup! Petit test:
$r		= "Malls.uid IN (1) AND COUNT(Stores.toto)>3 && Deals.value<=Accounts.credit";
preg_match_all("/(?<!')[A-Z]\w+s/", $r, $m);
print_r($m);
Done:
Array
(
    [0] => Array
        (
            [0] => Malls
            [1] => Stores
            [2] => Deals
            [3] => Accounts
        )

)
J'ai juste modifié le regexp, mes tables "peuvent" ne pas se terminer par "S".
Petite question: Le résultat est un tableau de tableau contenant le résultat... Pourquoi? Ca ne me dérange pas d'y accéder en $m[0][0], mais je ne saisis pas si j'ai fait une bourde ou quoi?

Dernière question: j'ai modifié ton regexp pour qu'il marche avec mon truc, j'ai dû enlever le \. de la fin pour exclure le point de mes résultats... Du coup la condition "fini par un point" n'existe pas. Comment faire pour lui dire, mais "en dehors" du delimiter, pour qu'il le vérifie mais ne l'inclut pas dans les résultat (Donc "Totos" et non "Totos." dans le résultat)?

J'ai essayé /(?<!')([A-Z]\w+s)\./ pour capturer ce qui est entre les parenthèses (Et donc pas le point, malgré son interet pour le test)... Mais ça me donne un double tableau de résultats: l'un sans les points, l'autre avec les points...

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:22
par stealth35
c'est le preg_match_all qui fait ca, c'est parce que y'a pas de groupe de capture que ca te perturbe

si tu fais :
$r = "Malls.uid IN (1) AND COUNT(Stores.toto)>3 && Deals.value<=Accounts.credit";
preg_match_all("/(?<!')([A-Z])(\w+)/", $r, $m);
print_r($m);
tu va avoir 3 groupes

le 1er étant toujours la chaine qui correspond au pattern
le 2eme le 1er goupe
le 3eme le 2 groupe

:wink:

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:38
par hickscorp
c'est le preg_match_all qui fait ca, c'est parce que y'a pas de groupe de capture que ca te perturbe
Yes je viens de capter :D Merci.

Alors j'ai fait quelques modifs... Pour tenter une exception:
$r		= "Table1.a IN (1) AND COUNT(Table2.b)>3 OR Table3.pupu=4839.32 AND 'Faux1.haha'='Faux2.hoho'";
preg_match_all('/(?<!\'!")([A-Z]\w+)\./', $r, $m);
echo '<pre>';
print_r($m);
echo '</pre>';
Cela donne:
Array
(
    [0] => Array
        (
            [0] => Table1.
            [1] => Table2.
            [2] => Table3.
            [3] => Faux1.
            [4] => Faux2.
        )
    [1] => Array
        (
            [0] => Table1
            [1] => Table2
            [2] => Table3
            [3] => Faux1
            [4] => Faux2
        )
)
Comment puis-je exclude les guillemets simples ou doubles? Je pensais qu'en ajoutant !\'!" ça fonctionnerait, mais non...

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:49
par stealth35
comme ca
preg_match_all('/(?<![\'"])([A-Z]\w+)\./', $r, $m);

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:50
par hickscorp
comme ca
preg_match_all('/(?<![\'"])([A-Z]\w+)\./', $r, $m);
J'ai dû trouver à peu près en même temps que tu as posté que j'avais oublié le OU dans mon regexp XD
Du coup j'ai corrigé en:
preg_match_all('/(?<!\'|!")([A-Z]\w+)\.\w/', $r, $m);

Mais ta version est plus claire... Merci beaucoup man :)

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 15:56
par hickscorp
comme ca
preg_match_all('/(?<![\'"])([A-Z]\w+)\./', $r, $m);
Haha... Je viens de trouver une autre exception:
$r = "Table1.a IN (1) AND COUNT(Table2.b)>3 OR Table3.pupu=4839.32 AND Table4.haha LIKE 'hmm... Faux1.bah hmm.'";
Faux1 est reconnu comme juste, puisque les guillemets ne sont pas collés à la fausse table name...
Une idée STP chèr(e) master du regexp? :)

[EDIT]Jserais presque tenté d'aller regarder les sources du parser SQL de MySQL... Il y aurait de grandes chances qu'il fasse pareil que ce que je cherche au moment du preparsing des requettes...[/EDIT]

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:05
par stealth35
la ca deviens chaud, c'est pour faire quoi a la base ?

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:09
par hickscorp
la ca deviens chaud, c'est pour faire quoi a la base ?
Ben je bosse sur une couche d'abstraction de base de donnée assez complexe. Avant de générer des requêtes, je souhaite parser les conditions WHERE / HAVING, afin que le constructeur de requête puisse déterminer quelles tables sont utilisées dans la requête, pour ensuite être en mesure de n'inclure que les jointures automatiques nécéssaires et pas toutes.

[EDIT]Je m'exprime très mal. En gros:
- Le constructeur de requête connaît toutes les relations entre tables,
- Il peut donc construire une requête à ralonge, qui syntaxiquement parlant sera juste et sans erreur, mais avec un overhead de malade pour le serveur SQL puisque certains objets peuvent avoir jusque 17 jointures...
- Je souhaite donc déterminer quelles jointures inclure (ou non) en fonction des conditions (Donc tables) présentes dans les clauses WHERE et HAVING :)

Est-ce que je suis réellement claîr? :D[/EDIT]

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:14
par stealth35
normalement les requêtes tu dois mettre un ` autour des champs, pour le reste si tu regarde du coté de Doctrine tout l'ORM se base sur le DQL, il va juste chercher les champs dans la fonction "where"

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:20
par hickscorp
normalement les requêtes tu dois mettre un ` autour des champs,
"Je" met toujours un ` autours de mes champs. Les développeurs qui utilisent mon framework, non :)
pour le reste si tu regarde du coté de Doctrine tout l'ORM se base sur le DQL, il va juste chercher les champs dans la fonction "where"
Oui j'ai pas mal bossé avec... Mais dans le projet dont je parle certaines contraintes techniques n'étaient pas satisfaisantes avec Doctrine ou PhpActiveRecord...

Pour en revenir au shmilblick, je vais essayer de décortiquer le parser MySQL à la recherche de leur routine d'éclatement de conditions...

Dans tous les cas, je te remercie grandement pour ton aide très utile (Je vais choisir ta dernière réponse comme étant la bonne, histoire quand même que tu n'aies pas perdu ton temps =D)

Pierrot.

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:25
par stealth35
faut voire aussi a quelle moment peux suivre un nom de table,
doit y 'avoir FROM, JOIN, INTO, HAVING, UPDATE, TABLE
si t'en vois d'autre ...

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:30
par hickscorp
faut voire aussi a quelle moment peux suivre un nom de table,
doit y 'avoir FROM, JOIN, INTO, HAVING, UPDATE, TABLE
si t'en vois d'autre ...
Uniquement WHERE et HAVING (Puisque les conditions sont fournies au framework par le developeur et uniquement les conditions).
Les FROM, JOIN, INTO, UPDATE... Sont générés par le framework en fonction des conditions.

Re: Regexp pour extraire le nom des tables d'une chaîne.

Posté : 21 oct. 2010, 16:37
par stealth35
donc il est obligé de mettre le nom des tables dans les where ?

EDIT : et si tu supprime d'hab tout ce qui est entre guillemet ?

EDIT 2 : comme ca
$r = "Table1.a IN (1) AND COUNT(Table2.b)>3 OR Table3.pupu=4839.32 AND Table4.haha LIKE 'hmm... Faux1.bah hmm.'";
$r = preg_replace('/([\'"])[^\1]+\1/', '', $r);
preg_match_all('/\x60?([A-Z]\w+)\x60?\./', $r, $m);
print_r($m);