Regexp Vim

La question :

Bonjour,

Je cherche comment écrire une regexp sous Vim pour reformater un bout
de code source et je n'arrive pas trop à m'en sortir. J'ai mis un x-
post sur fco.unix parce que je sais que pas mal d'habitués y trainent,
mais le suivi est sur fca.editeurs-de-texte.

J'ai un fichier de code source en C++, où les noms de fonction sont du
type Classe::nomDeFonction() et je veux le reformater en
Classe::nom_de_fonction(). Il se trouve que les fonctions de cette
classe ne sont presque pas appelées par la classe elle-même, donc je
n'ai à me préoccuper (dans ce fichier du moins) que des entêtes de
fonction, pas des appels.

Pour identifier ces lignes, je peux faire une recherche comme ça (j'ai
rajouté des espaces pour rendre les choses lisibles, mais je ne les
mets évidemment pas en vrai) :
/:: \([a-z]\+\) \( \([A-Z]\) \([a-z]\+\) \) (
Je cherche :: suivi d'un mot en minuscule puis de au moins un mot
commençant par une majuscule suivi de minuscules, et enfin une
parenthèse ouvrante.

Bon, je pourrais utiliser des trucs plus génériques que [a-z] mais
dans mon cas, j'ai que des lettres dans les noms, donc ça marche très
bien. De toute façon, ça n'est pas la recherche qui me pose problème.

Par contre, pour le remplacement, je sèche un peu sur l'aspect
groupements imbriqués. Je ne sais pas comment récupérer tous les blocs
de \( \([A-Z]\) \([a-z]\+\) \)\+ : \1 contient tout le bloc externe
(le dernier mot), \2 contient la dernière majuscule, \3 les minuscules
du dernier mot, mais comment faire pour avoir les autres mots ?

J'ai bidouillé en plusieurs étapes, en considérant d'abord que je n'ai
qu'un seul mot à remplacer (::parExemple() devenant ::par_exemple()) :
:.s/::\([a-z]\+\)\([A-Z]\)\([a-z]\+\)(/::\1_\l\2\3(/g
Puis en prenant deux mots à remplacer :
:.s/::\([a-z]\+\)\([A-Z]\)\([a-z]\+\)\([A-Z]\)\([a-z]\+\)(/::\1_\l\2\3_
\l\4\5(/g
etc.

Comme dans mon cas je ne vais pas au delà de 3 mots, ça n'a pas été
trop compliqué, mais je suis un peu vexé de ne pas avoir trouvé
comment faire une expression unique.

Est-ce que quelqu'un à une idée de comment j'aurais pu faire mon
remplacement en une seule fois ?

Merci !
--
Rémi Moyen

Poser votre question sur le forum Logiciels

Les 5 réponses :

On Oct 11, 11:58 am, Rémi Moyen <rmo...@gmail.com> a écrit :


Pour identifier ces lignes, je peux faire une recherche comme ça (j'ai
rajouté des espaces pour rendre les choses lisibles, mais je ne les
mets évidemment pas en vrai) :
/::    \([a-z]\+\)    \(  \([A-Z]\)    \([a-z]\+\)  \)    (


Évidemment, j'ai réussi à me planter dans mes copier/coller de mon
historique de vi... Il manque un \+ à la fin (sinon ça ne marche que
si il y a une seule majuscule dans le nom). J'aurais dû mettre :
/::    \([a-z]\+\)    \(  \([A-Z]\)    \([a-z]\+\)  \)\+    (

Ça ne change rien au reste de ma question. Désolé pour l'erreur...
--
Rémi Moyen

Le 11/10/2010 12:58, Rémi Moyen a écrit :



Je cherche comment écrire une regexp sous Vim pour reformater un bout
de code source et je n'arrive pas trop à m'en sortir. J'ai mis un x-
post sur fco.unix parce que je sais que pas mal d'habitués y trainent,
mais le suivi est sur fca.editeurs-de-texte.


Pour ma part je fais une diapublication avec fr.comp.lang.regexp et j'y
place le suivi.


J'ai un fichier de code source en C++, où les noms de fonction sont du
type Classe::nomDeFonction() et je veux le reformater en
Classe::nom_de_fonction(). Il se trouve que les fonctions de cette
classe ne sont presque pas appelées par la classe elle-même, donc je
n'ai à me préoccuper (dans ce fichier du moins) que des entêtes de
fonction, pas des appels.

Pour identifier ces lignes, je peux faire une recherche comme ça (j'ai
rajouté des espaces pour rendre les choses lisibles, mais je ne les
mets évidemment pas en vrai) :
/:: \([a-z]\+\) \( \([A-Z]\) \([a-z]\+\) \) (
Je cherche :: suivi d'un mot en minuscule puis de au moins un mot
commençant par une majuscule suivi de minuscules, et enfin une
parenthèse ouvrante.

Bon, je pourrais utiliser des trucs plus génériques que [a-z] mais
dans mon cas, j'ai que des lettres dans les noms, donc ça marche très
bien. De toute façon, ça n'est pas la recherche qui me pose problème.


Ok.


Par contre, pour le remplacement, je sèche un peu sur l'aspect
groupements imbriqués. Je ne sais pas comment récupérer tous les blocs
de \( \([A-Z]\) \([a-z]\+\) \)\+ : \1 contient tout le bloc externe
(le dernier mot), \2 contient la dernière majuscule, \3 les minuscules
du dernier mot, mais comment faire pour avoir les autres mots ?

J'ai bidouillé en plusieurs étapes, en considérant d'abord que je n'ai
qu'un seul mot à remplacer (::parExemple() devenant ::par_exemple()) :
:.s/::\([a-z]\+\)\([A-Z]\)\([a-z]\+\)(/::\1_\l\2\3(/g


Wouaouh ! Je ne connaissais pas le \l des regexp Vim !


Puis en prenant deux mots à remplacer :
:.s/::\([a-z]\+\)\([A-Z]\)\([a-z]\+\)\([A-Z]\)\([a-z]\+\)(/::\1_\l\2\3_
\l\4\5(/g
etc.

Comme dans mon cas je ne vais pas au delà de 3 mots, ça n'a pas été
trop compliqué, mais je suis un peu vexé de ne pas avoir trouvé
comment faire une expression unique.

Est-ce que quelqu'un à une idée de comment j'aurais pu faire mon
remplacement en une seule fois ?


Oui, il faut utiliser des assertions pour ne pas consommer les
caractères :: et ( qui nous servent plusieurs fois. Je ne savais pas que
ça existait dans Vim, mais je viens de le découvrir : ils appellent ça «
matches with zero width » et utilisent \@ (plus quelque chose) derrière
l'assertion.

<http://vimdoc.sourceforge.net/htmldoc/pattern.html#/\@=>
<http://vimdoc.sourceforge.net/htmldoc/pattern.html#/\@%3C=>

Résultat :
:.s/\%(::[A-Za-z]*[a-z]\)\@<=\([A-Z]\)\%([a-z][A-Za-z]*(\)\@=/_\l\1/g

Explications :

\%(::[A-Za-z]*[a-z]\)\@<=
On veut qu'avant le point courant il y ait :: suivi de lettres,
la dernière lettre étant une minuscule.

\([A-Z]\)
On veut une majuscule, celle-ci est capturée dans \1

\%([a-z][A-Za-z]*(\)\@=
On veut qu'après la majuscule capturée il y ait des lettres avant
une parenthèse ouvrante, la première lettre étant une minuscule.

_\l\1
La majuscule capturée est mise en minuscule et précédée de _


Cordialement,
--
Olivier Miakinen

Le 11/10/2010 12:58, Rémi Moyen a écrit :


Bonjour,

Je cherche comment écrire une regexp sous Vim pour reformater un bout
de code source et je n'arrive pas trop à m'en sortir. J'ai mis un x-
post sur fco.unix parce que je sais que pas mal d'habitués y trainent,
mais le suivi est sur fca.editeurs-de-texte.

J'ai un fichier de code source en C++, où les noms de fonction sont du
type Classe::nomDeFonction() et je veux le reformater en
Classe::nom_de_fonction(). Il se trouve que les fonctions de cette
classe ne sont presque pas appelées par la classe elle-même, donc je
n'ai à me préoccuper (dans ce fichier du moins) que des entêtes de
fonction, pas des appels.


Bonjour,

quid de le faire en 2 passes ?

:g/::/s/[_A-_Z]/_&/g
:%s/_Classe::/Classe::/

sinon, il semble que vim ne supporte pas les ERE, aupire, c'est un mixe
entre les BRE et les ERE.

comme le dit l'aide en ligne, le + se rapporte à un atom et non à un groupe.
par ex. : s/\(a\+\)/_\1/ fonctionne, mais pas s/\(a\)\+/_\1/

sinon, en ce qui concerne les histoire de \1, etc.
compte les ( ouvrantes, si plus de 9 (, il est surement possible d'en
protéger certaines avec un % tel que \%(, cela fait un de moins.
par ex. : \(a\(b\(c\)\)\) : \1 = abc, \2 => bc, \3 => c
\(a\%(b\(c\)\)\) : \1 => abc, \2 => c

PS : pour limiter les \, passe en verynomagic,
par ex. : \(a\+\(b\(c\)\)\) en magic vs \v(a+(b(c))) en verynomagic

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%d
supprimer "%nospam% et ".invalid" pour me repondre.

On Oct 12, 4:04 am, Cyrille Lefevre <cyrille.lefevre-news
%nos...@laposte.net.invalid> a écrit :


Le 11/10/2010 12:58, Rémi Moyen a écrit :



quid de le faire en 2 passes ?


Ben disons que c'est plus de la curiosité qu'un besoin (vu que j'ai
résolu le problème en le faisant en 2 ou 3 fois avec des longueurs
variables)... Mais oui, pourquoi pas aussi.


:g/::/s/[_A-_Z]/_&/g


Hum, c'est pas parfait. D'abord parce que ça ne convertit pas les
majuscules en minuscules et ensuite parce que si j'ai des
Classe::une_fonction(), ça les transforme en _classe::une__fonction()
(avec deux _). Ce que je veux en fait, c'est :

:g/::/s/[A-Z]/_\l&/g


:%s/_Classe::/Classe::/


Oui, ça marche effectivement. Je n'avais pas pensé à ça. C'est un peu
mieux que ma solution initiale, mais... ça n'est pas parfait !
D'un point de vue curiosité intellectuelle, je préfère la solution
d'Olivier (voir la suite de la discussion sur fr.comp.lang.regexp).
Bon, d'un point de vue pratique, j'ai compris ta solution tout de
suite alors que je suis encore en train de discuter avec Olivier pour
comprendre les détails !


comme le dit l'aide en ligne, le + se rapporte à un atom et non à un groupe.
par ex. : s/\(a\+\)/_\1/ fonctionne, mais pas s/\(a\)\+/_\1/


Ben oui, c'est entre autres pour ça que je n'arrivais pas à trouver de
solution. Je me demandais si il existait une syntaxe qui permettrait
de faire, en gros, s/\(a\)\+/\1\2\3...\N/ (i.e. que chaque occurrence
du motif dupliqué par \+ soit référencé dans le motif de
remplacement). Mais ça n'a pas l'air d'exister.


sinon, en ce qui concerne les histoire de \1, etc.
compte les ( ouvrantes, si plus de 9 (, il est surement possible d'en
protéger certaines avec un % tel que \%(, cela fait un de moins.


Voui, je sais. J'ai juste pas l'habitude de l'utiliser (et rarement le
besoin, je n'ai en général guère plus de 2 ou 3 blocs).


PS : pour limiter les \, passe en verynomagic,


J'ai aussi découvert hier en cherchant des infos sur mon motif de
remplacement. Bon, ça ne me gène pas trop, j'ai l'habitude, mais je
garde ça dans un coin pour décrypter les motifs un peu trop surchargés
en \.

Merci !
--
Rémi Moyen

Le 12/10/2010 10:36, Rémi Moyen a écrit :


Hum, c'est pas parfait. D'abord parce que ça ne convertit pas les
majuscules en minuscules et ensuite parce que si j'ai des
Classe::une_fonction(), ça les transforme en _classe::une__fonction()
(avec deux _). Ce que je veux en fait, c'est :

:g/::/s/[A-Z]/_\l&/g


Bonjour,

argh! l'expression d'origine était bonne, mais comme je l'ai joué puis
fait le copier coller, elle n'était plus bonne
sinon, pas vu l'histoire de la conversion...

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%d
supprimer "%nospam% et ".invalid" pour me repondre.

Poser votre question sur le forum Logiciels

Questions similaires :