Efficacité des Regex pour le remplacement d'occurrences? [Général] - Divers - Programmation
Marsh Posté le 19-07-2006 à 16:35:10
Je suppose que ça dépend fortement du contexte; c-a-d est-ce que la chaîne auras toujours le même format? Est-ce que la chaîne a des mots clés interchangeables ou ce genre de joyeusetés?
Marsh Posté le 19-07-2006 à 16:38:58
Bah ici, il s'agit de chaînes simples.
Du genre chercher des mots dans un paragraphe, ou alors des balises dans un texte.
De toute manière, dès que ça devient compliqué (les "joyeusetés" dont tu me parles), il n'est plus possible de faire une simple recherche par itération (ou alors, ça devient le bronx)
Donc, ma question concerne uniquement la recherche de chaînes simples dans d'autres chaînes.
Marsh Posté le 19-07-2006 à 16:41:20
Yoyo@ a écrit : Salut, je me posais une question sur l'efficacité des Regex. |
Non... Rien que sur les deux premiers langages que tu cites cela n'a rien a voir! D'autant plus que sur le php, cela dépend des fonctions que tu utilises (ereg* vs preg*)
Et puis de toute façon:
masklinn a écrit :
|
Marsh Posté le 19-07-2006 à 17:25:59
anapajari a écrit : Non... Rien que sur les deux premiers langages que tu cites cela n'a rien a voir! D'autant plus que sur le php, cela dépend des fonctions que tu utilises (ereg* vs preg*) |
Oui, c'est vrai.
Mais je pensais que ma question avait une réponse générale (que je suspecte être en faveur de la méthode itérative "à l a main" )
Alors, disons que je me place du côté de PHP et des preg* (qui sont plus efficaces il me semble que les ereg*)
Marsh Posté le 19-07-2006 à 18:19:14
Pour moi, la différence se situe essentiellement dans la maintenabilité du code.
En PERL, entre un "$chaine =~ s/search/replace", et un "$chaine = join ' ', grep { $_ ne "truc" ? $_ : "" } split ' ', $chaine" (exemple vraiment à la con), j'ai vite choisi.
L'inverse est vrai aussi.
Par contre, côté performances, j'attends une étude comparative qui montre clairement un retrait important (et non de quelques inutiles pouillèmes) des regexp sur des méthodes implémentées maison (et qui étendent souvent la non-maintenabilité sur plein de lignes, contre une ou deux pour les regexp).
Marsh Posté le 19-07-2006 à 18:29:40
Elmoricq a écrit : Pour moi, la différence se situe essentiellement dans la maintenabilité du code. |
Ouh là, ton deuxième exemple en Perl est très loin de faire ce qu'il faudrait... Il marcherait à la limite (syntaxe à vérifier) lorsque la chaîne à chercher est un mot (séparé par des espaces donc)
Mais si on veut que l'exmple soit général, je ne vois pas d'autres manières que d'utiliser un indice et des substr.
Sinon, pour en revenir à ma question d'efficacité, c'est bien dommage de ne pas avoir de réponse, car je n'ai absolument aucune idée de ce qui est sous jacents avec les Regexp, les mécanismes employés, les algo etc, et donc également aucune idée de l'efficacité selon le contexte.
Marsh Posté le 19-07-2006 à 20:12:33
J'ai bien fait de préciser qu'il s'agissait d'un exemple stupide, parce que je voyais gros comme une maison qu'il allait occulter le reste du message.
Marsh Posté le 19-07-2006 à 22:12:15
Oui, oui, bien entendu.
Mais donc, au final, ça ne me dit pas ce qui serait le plus efficace...
De faire des recherches de substrings sur ma string principale et de faire des remplacements au fur et à mesure de manière itérative, ou alors d'utiliser un Regex telle que celle que tu as donnée...
En fait, quelque part, je me dis qu'il n'y a pas de miracle, et qu'une Regex ne pourra pas faire mieux que de le faire à la main de manière itérative...
Marsh Posté le 19-07-2006 à 22:36:18
Evidemment, dans des cas simples, une recherche à base de substr()/replace() est tout aussi envisageable qu'une regex.
C'est même préférable, selon le langage. En C, par exemple. Mais c'est plus pour une raison de simplicité d'écriture.
Quant aux performances d'une regex sur un search&replace, je doute qu'elle fasse pire, ou alors c'est difficilement mesurable.
Peut-être que sur une chaîne de quelques centaines de Mo on trouverait une différence significative ? Je ne sais pas, et j'ai la flemme de tester.
En plus, j'aime à croire que ceux qui implémentent les moteurs de regex sont pas des débutants en programmation/algorithmique, ce qui leur donne un avantage certain dès que les choses se compliquent, par rapport à du "fait main pour l'occasion".
Ajoutons encore dans le chaudron l'ingrédient "on a assez de travail sans en plus réinventer la roue", et il devient plus difficile de chercher un désavantage aux regexp, par rapport à une implémentation maison.
Le seul problème de la regex, c'est que certains y voient une solution magique, et oublient parfois de réfléchir à leur problème avant d'utiliser cet outil. Ca mène à de bons désastres parfois.
Marsh Posté le 19-07-2006 à 22:56:13
Elmoricq a écrit : |
Bah dans mon cas, qui est très simple, je ne vois pas comment une Regex pourrait être plus efficace, je n'arrive pas à envisager le genre de traitement qu'elle pourrait faire...
Elmoricq a écrit : |
Je suis d'accord avec toi, mais dans mon cas à moi, la problêmatique est tellement simple que le faire soit même n'est pas une perte de temps... Je ne parle pas ici de Regex complexes, qui capturent des patterns, avec quatifieurs et autres classes de caractères...
Je cherche juste (et en fait, je ne cherche même pas à le faire, mais je me posais la question allors que je lisais du code qui se contente d'utiliser des Regex dans tous les sens) à savoir quel est le plus efficace pour remplacer toutes les occurrences dun mot x par un mot y dans une chaîne z...
Marsh Posté le 19-07-2006 à 23:05:01
Yoyo@ a écrit : Bah dans mon cas, qui est très simple, je ne vois pas comment une Regex pourrait être plus efficace, je n'arrive pas à envisager le genre de traitement qu'elle pourrait faire... |
Certes, mais il n'y a pas non plus de raison qu'elle soit moins efficace.
Yoyo@ a écrit : Je suis d'accord avec toi, mais dans mon cas à moi, la problêmatique est tellement simple que le faire soit même n'est pas une perte de temps... Je ne parle pas ici de Regex complexes, qui capturent des patterns, avec quatifieurs et autres classes de caractères... |
Et dans ce cas-là, mon avis est que c'est la simplicité d'écriture qui doit primer.
En PERL, une regexp c'est mieux.
En Java, y a pas de "mieux", vu que String implémente replace() et replaceAll() qui sont de sympathiques fonctions simplifiant grandement la vie.
Autre exemple, en C, j'ai créé ma fonction stringreplace() dans ma bibliothèque-outils, parce qu'en standard ce sont les ignobles regex POSIX qui sont en vigueur, et personnellement je les évite le plus souvent possible (en PHP, Java etc, ce sont les regex PERL qui sont utilisées, et c'est autre chose )
Bref, sur les cas simples, pas de règle clairement établie. Dans tous les cas, faut aller au plus simple.
Yoyo@ a écrit : Je cherche juste (et en fait, je ne cherche même pas à le faire, mais je me posais la question allors que je lisais du code qui se contente d'utiliser des Regex dans tous les sens) à savoir quel est le plus efficace pour remplacer toutes les occurrences dun mot x par un mot y dans une chaîne z... |
Encore une fois, je doute que tu trouves une quelconque différence lors d'un usage courant.
Marsh Posté le 20-07-2006 à 07:42:43
Elmoricq a écrit : Certes, mais il n'y a pas non plus de raison qu'elle soit moins efficace. |
Bah au moins légèrement moins efficace, vu que l'outil est générique, il faut bien qu'il y ait quelques tests internes pour que le moteur de Regex se "rende compte" qu'il est dans un cas simple
Mais bon, en bref, si je sais me servir de mes Regex, même pour des cas simples,, utant les utiliser, c'est ça la conclusion?
Sinon, j'ai une question: tu sembles ne pas aimer les Regex selon la norme POSIX. Why? Pour ma part, j'utilise celles de la norme PERL quand je peux, mais c'est simplement parce que j'ai vraiment commencé à uttiliser des Regex compliquées avec Perl.
Enfin, je vois que tu t'es créé une librairie avec des fonctions "outils" en C. Tu y as mis quoi comme genre de fonctions dedans? Je trouve que l'idée est bonne, si tu arrives à détecter des routines dont tu te sers souvent. Et tu les intègres comment? Copier/coller du code source de la routine qui t'intéresse de ta librairie dans ton projet, ou alors inclusion de ta librairie?
Marsh Posté le 20-07-2006 à 09:57:58
Yoyo@ a écrit : Mais bon, en bref, si je sais me servir de mes Regex, même pour des cas simples,, utant les utiliser, c'est ça la conclusion? |
Euh... ben non, je dis justement que c'est à juger au cas par cas, selon le traitement à faire et le langage utilisé...
Yoyo@ a écrit : Sinon, j'ai une question: tu sembles ne pas aimer les Regex selon la norme POSIX. Why? |
Parce qu'elles sont à chier.
Yoyo@ a écrit : Enfin, je vois que tu t'es créé une librairie avec des fonctions "outils" en C. Tu y as mis quoi comme genre de fonctions dedans? Je trouve que l'idée est bonne, si tu arrives à détecter des routines dont tu te sers souvent. |
En C, c'est même requis si tu veux commencer à être productif.
Y a rien, de base. Pas même une fonction pour lire une ligne entière sur un flux (avec allocation dynamique).
Donc à force, on maintient une bibliothèque de fonctions, qu'on améliore au fil du temps et des expériences. De temps en temps quand je m'ennuie, je fais même de la micro-optimisation dessus pour me palucher sur l'élégance du code.
Yoyo@ a écrit : Et tu les intègres comment? Copier/coller du code source de la routine qui t'intéresse de ta librairie dans ton projet, ou alors inclusion de ta librairie? |
Le but d'une bibliothèque, c'est justement de ne pas faire de copier-coller.
On inclut la bibliothèque au projet, et on utilise les fonctions comme si de rien n'était. Et vu que dans la plupart des cas on compile en dynamique, il suffit de modifier/corriger/améliorer une bibliothèque pour modifier/corriger/améliorer du même coup tous les programmes qui l'utilise (genre les DLL sous Windows, ce sont des bibliothèques, et sous *nix, ce sont les .so).
D'ailleurs en programmant tu utilises des bibliothèques sans le savoir. En C, du moment que tu fais quoique ce soit en dehors de int main(void) { return 0 }, tu utilises au minimum la libC...
Marsh Posté le 20-07-2006 à 10:28:00
Elmoricq a écrit : Euh... ben non, je dis justement que c'est à juger au cas par cas, selon le traitement à faire et le langage utilisé... |
Bah oui, mais bon, comment veux tu juger si tu ne sais pas comment les Regex marchent en interne, et surtout si ça dépend du langage. Après, le choix se fait juste au feeling je suppose (à moins d'en connaître les mécanismes)
Elmoricq a écrit : |
Oui, oui, ne t'étrangle pas
Je me doutais bien que tu utilisais une liaison dans ton projet, mais je demandais au cas où; surtout que tu parlais d'une librairie (unique donc) qui peut grossir, et si tu n'as pas envie d'inclure un gros DLL à ton projet, car tu n'utilises qu'une ou deux routines. Alors peut être faire une liaison statique incluse dans ton exécutable.
Elmoricq a écrit : |
Oui, oui, no problem.
Merci pour tes réponses en tout cas.
Marsh Posté le 20-07-2006 à 10:55:02
Pour Perl je dirais Regex mieux mais comme déjà dit ça dépent des cas. Pour les autres langages je sais pas
Marsh Posté le 20-07-2006 à 11:13:11
je me demandais aussi ce qui allait le plus vite alors j'ai fait "a la va-vite" un petit bench en perl/php.
$text contient dans les 2 cas, 1500 fois la ligne "La petite maison dans la prairie", et on remplace prairie par foret partout.
En perl:
Code :
|
=> 0.000621 ms
Code :
|
=> 0.192977 ms
En php
Code :
|
=> 0.000991 ms
Code :
|
=> 0.000282 ms
Bilan: ... aucun c'était juste pour voir
Marsh Posté le 20-07-2006 à 11:16:54
1500x c'est pas assez pour tester.
Et de toute façon, pour le PERL la première méthode est clairement plus indiquée car plus lisible, et en PHP, je préfèrerais la seconde d'un pouillème plus lisible.
Maintenabilité > Performances.
Surtout que dans 99%, les différences de perfs se jouent sur les algorithmes.
Marsh Posté le 20-07-2006 à 11:21:59
Théoriquement une regexp tu aura une perte de temps au "début" de la fonction le temps d'analyser la chaine, d'en déduire un automate, éventuellement de le minimaliser... mais ensuite tout le travail se fait en builtin/en interne.
Alors que des substr&co ca va faire plein d'appels de fonctions et de créations de strings "dans l'interpréteur" s'il s'agit d'un langage interpreté (donc perl, php, etc...) qui sont plus couteux généralement (ca dépends des langages ca mais bon...) que du travail en interne et donc probablement plus lents.
L'exemple typique est celui d'anaparji, ou dans sa méthode avec perl, il crée énorméments de strings intermédiaires, appelle plusieurs fonctions, et tout cela étant en interpreté, ca induit pas mal de boulot.
La regexp d'une chaine simple ou un str_replace ala php font sensiblement le même boulot, mais le font en C (le langage dans lequel a été codé l'interpréteur php ou perl) ou les appels de fonctions et la création de strings temporaires sont nettement moins couteux.
Marsh Posté le 20-07-2006 à 11:45:59
Elmoricq a écrit : 1500x c'est pas assez pour tester. |
Ok ok
Avec 100 000 lignes
SRVTEST bench # php a.php |
Avec 1 000 000 lignes:
|
Elmoricq a écrit : Maintenabilité > Performances. |
Marsh Posté le 21-07-2006 à 08:33:12
anapajari a écrit :
|
Ca ne me paraît pas hyper optimal ça. Tu pourrais essayer de te servir du résultat du premier "index($text,'prairie')" au lieu de faire un second appel à la même procédure.
D'autre part, je vois que tu utilises à chaque fois l'offset 0, donc, je suppose (même si je ne sais pas comment c'est fait en interne) que Perl va à chaque fois analyser la phrase depuis le début, alors qu'on "sait" que prairie ne sera plus contenu au début de la phrase...
Sinon, au global, la différence entre ton appel "non Regexp" PHP et ton appel "non Regexp" Perl, c'est qu'en Perl, tu fais un truc à la main, alors qu'en PHP, tu appelles une unique fonction, qui fait donc tout en interne.
Marsh Posté le 21-07-2006 à 08:38:16
anapajari a écrit : Ok ok
|
Tiens, c'est quoi ce "SRVTEST"? Une procédure de bench?
Marsh Posté le 21-07-2006 à 09:19:12
Yoyo@ a écrit : Ca ne me paraît pas hyper optimal ça. Tu pourrais essayer de te servir du résultat du premier "index($text,'prairie')" au lieu de faire un second appel à la même procédure. |
Ben réécrit sa procédure de tests
Mais bon, tu te prends vraiment la tête pour rien, et ça prouve surtout qu'il vaut mieux utiliser des outils qui ont été pensés et testés plutôt que de réinventer la roue à chaque fois.
Yoyo@ a écrit : Tiens, c'est quoi ce "SRVTEST"? Une procédure de bench? |
C'est le nom d'un serveur unix je pense.
Et à moins qu'il n'ait trafiqué son prompt, il est connecté en root. C'est mal.
Marsh Posté le 21-07-2006 à 09:30:55
Elmoricq a écrit : Ben réécrit sa procédure de tests |
C'était juste une remarque (quitte à faire des benchs pour tester différentes manières de faire, autant tenter de faire au mieux pour chaque manière, pour avoir des résultats fiables, même si dans notre cas, les résultats sont sans appel)
Sinon, c'est pas que je me prends la tête pour rien (cf mon post initial où finalment j'ai eu la réponse assez vite) mais c'est le topic qui est parti dans cette direction... (et je ne dis pas que c'est inintéressant, bien au contraire)
Elmoricq a écrit : |
Oki, oki... J'ai 0 expérience du monde Linux.
Donc, SRVTEST est le nom de son serveur, et bench est un script générique (qu'il a dû écrire) lui permettant de "benchmarker" ses scripts.
Marsh Posté le 21-07-2006 à 09:33:09
Je dirais plutôt que "bench" c'est le nom de son répertoire courant.
Et Unix != Linux. A partir d'un prompt on ne peut pas déduire de quel genre d'Unix il s'agit.
Marsh Posté le 21-07-2006 à 09:38:19
Elmoricq a écrit : Je dirais plutôt que "bench" c'est le nom de son répertoire courant. |
Bon, ok, chui trop curieux (et tu dois bien te marrer sous ta moustache )
Entre nous, tu crois vraiment qu'il dispose d'un serveur Unix non Linux sous la main? Allez, on va dire qu'il y a de grandes chance que ce soit du Linux, tu me l'accorderas?
Bon, question à 64000$: le #, c'est quoi? Ca veut dire que c'est l'user root?
Marsh Posté le 21-07-2006 à 09:44:37
Yoyo@ a écrit : Bon, ok, chui trop curieux (et tu dois bien te marrer sous ta moustache ) |
Je suis au boulot, et je bosse sur Solaris par exemple.
Et s'il est chez lui, il pourrait être sur FreeBSD, MacOS X, Solaris, Linux, etc.
Yoyo@ a écrit : Bon, question à 64000$: le #, c'est quoi? Ca veut dire que c'est l'user root? |
Sur un shell sh/ksh/bash de base, oui.
Marsh Posté le 21-07-2006 à 09:59:19
Oki, merci pour les infos
En tout cas, en voyant les benchs ci dessus, je me rends compte la différence de vitesse, pour les langages interprêtés, qu'il peut y avoir entre des fonctions incluses dans le langage (qui sont donc sans doute écrites dans le langage d'implémentation du langage, C pour PHP et Perl) et les fonctions que nous écrivons à la main. Wow, la claque.
J'avais regardé, à mes heures perdues, comment était écrit le langage Perl (et surtout la gestion des types de données) et c'est vrai qu'il y a des tonnes de traitements derrière les fagots.
Je me dis qu'au final, les modules Perl écrits en C doivent être autrement plus rapides que les modules écrits en Perl...
Marsh Posté le 21-07-2006 à 10:03:28
Yoyo@ a écrit : Tiens, c'est quoi ce "SRVTEST"? Une procédure de bench? |
Elmoricq a écrit : Ben réécrit sa procédure de tests |
+10
Elmoricq a écrit : C'est le nom d'un serveur unix je pense. |
S'mon serveur de test à moi du travail, j'en fais ce que je veux
Yoyo@ a écrit : C'était juste une remarque (quitte à faire des benchs pour tester différentes manières de faire, autant tenter de faire au mieux pour chaque manière, pour avoir des résultats fiables, même si dans notre cas, les résultats sont sans appel) |
Tu as raison c'est optimisable trente fois, vas-y amuse toi!!!
Yoyo@ a écrit : Donc, SRVTEST est le nom de son serveur, et bench est un script générique (qu'il a dû écrire) lui permettant de "benchmarker" ses scripts. |
Bench c'est le nom du repertoire où j'ai foutu ces machins
Yoyo@ a écrit : Entre nous, tu crois vraiment qu'il dispose d'un serveur Unix non Linux sous la main? Allez, on va dire qu'il y a de grandes chance que ce soit du Linux, tu me l'accorderas? |
Y'en a au boulot(des AIX si tu veux tout savoir), mais je suis pas root sur ceux la et pis c'est relou.
Donc pour les details le SRVTEST, c'est une gentoo
Marsh Posté le 21-07-2006 à 10:17:47
anapajari a écrit : |
Ouais, mais bon, 0.192977 ms divisé par 30, ça fait encore beaucoup trop
Bon, merci pour toutes ces infos les amis.
Ce fut intéressant
La conclusiuon, c'est qu'il n'y a pas de réponse universelle, même pour les cas simples.
Enfin, on est quand même d'accord, surtout pour les langages interprêtés, que s'il existe une routine de base (du Core quoi) pouvant faire ce que l'on veut, il vaut mieux, déja dans un soucis d'efficacité (je ne parle pas de lisibilité) l'utiliser...
(Si on était en C/C++, je ne serais pas aussi catégorique)
Marsh Posté le 21-07-2006 à 13:50:53
Yoyo@ a écrit : (Si on était en C/C++, je ne serais pas aussi catégorique) |
Pourquoi?? Tu peux remplacer toutes les occurences d'un mot par un autre (voir plusieurs) très simplement avec une string. Pour les cas simples, y'a pas à s'embrouiller avec les regex alors qu'on a un joli replace
Marsh Posté le 21-07-2006 à 13:51:49
Pas de replace en C.
Mais, bon, y a memmove qui est très pratique
Marsh Posté le 21-07-2006 à 14:05:22
IrmatDen a écrit : Pourquoi?? Tu peux remplacer toutes les occurences d'un mot par un autre (voir plusieurs) très simplement avec une string. Pour les cas simples, y'a pas à s'embrouiller avec les regex alors qu'on a un joli replace |
Non, ce que je voulais dire, c'est qu'en C/C++, il est possible d'avoir de bonnes vitesses d'exécution en implémentant les choses nous même, contrairement aux langages interprêtés, où, comme on pet le vois plus haut, faire les choses par nous mêmes peut prendre énormémemnt de temps par rapport à a fonctions en "natif".
Marsh Posté le 19-07-2006 à 16:06:36
Salut, je me posais une question sur l'efficacité des Regex.
Je pense que la réponse est indépendante du langage utilisé (Perl, PHP, JS ou autres Java)
Pour remplacer toutes les occurrences d'une chaîne str1 par une chaîne str2 dans une chaîne str3, vaut il mieux utiliser des Regex ou alors une itération avec des "strFind" et des "strReplace"? Je parle en terme d'efficacité et de rapidité bien entendu.
Le danger, je pense, avec les Regex, c'est que c'est tellement générique et puissant, que c'est une solution qui ne doit pas tout le temps être optimale pour des tâches simples....