Edition multlignes avec vim en mode visuel

a marqué ce sujet comme résolu.

Bonjour :)

J’essaye de me mettre sérieusement à vim et je suis tombé sur une édition que je n’arrive pas à faire correctement.

J’ai copié un bout de XML qui contient une multitude de tags simples (plusieurs milliers de lignes).

<TAGA>Value1</TAGA>
<TAGA>Value2</TAGA>
<TAGA>Value3</TAGA>
...
<TAGB>Value10</TAGB>
<TAGB>Value11</TAGB>
...

Je souhaite transformer ce bout de texte de la manière suivante :

function("Value1")
function("Value2")
function("Value3")
...
function("Value10")
function("Value11")
...

En gros supprimer les balises XML et rajouter du texte avant la valeur du tag (function(") et après (").

Pour faire cela avec vim, j’ai voulu passer par le mode "visuel block" (Ctrl+v). J’ai réussi à faire la moitié du chemin : supprimer la balise ouvrante et insertion du text (function("). Pour cela j’ai fait comme ça :

Ctrl+v            " Passage en mode visuel block
G                 " Sélectionne tout les lignes jusqu'à la fin du fichier
f>                " Sélectionne le text jusqu'au chevron > pour sélectionner la balise ouvrante
cfunction("<Esc>  " Remplace la balise ouvrante par le texte

Cela marche pour le moment, mais ça pose problème si j’ai des tags dont les noms n’ont pas les même nombres de caractères.

Pour la suppression de la balise fermante là je séché. Vue que les valeurs dans les tags n’ont pas les mêmes nombre de caractères cela pose problème.

En faite pour ce genre de chose avec un éditeur tel que vscode, j’utiliserai le multicurseur, irait à la fin de la ligne pour chaque ligne avec la touche <End> et ferais un Ctrl+Shift+Flèche-gauche pour sélectionner sur chaque lignes exactement la balise fermante du tag (Ctrl+Shift permet de sélectionner en se déplaçant par mot). Cela a l’avantage de fonctionner aussi si les noms des tags n’ont pas le même nombre de caractères.

J’ai l’impression que l’approche mode visuel n’est peut être pas adapté à ce cas de figure. Du coup question aux utilisateurs de vim. Comment auriez-vous fait?

Merci :)

Salut,

Je ferais une macro sur une ligne puis je l’exécuterais N fois. En l’occurrence qq0cf>function("^[f<c$")^[jq1000@q (où ^[ est équivalent à <Esc> que tu utilises probablement, voir :help ^[). Explication :

  • qq commence à enregistrer dans la macro q ;
  • 0 va au début de la ligne courante ;
  • cf> efface jusqu’au prochain > inclus et se met en insertion ;
  • function(" est le texte à la place de la première balise ;
  • ^[ retourne en normal mode ;
  • f< va au prochain < ;
  • c$ efface jusqu’à la fin de la ligne et se met en insertion ;
  • ") est le texte à la place de la deuxième balise ;
  • ^[ retourne en mode normal ;
  • j va à la ligne suivante ;
  • q termine l’enregistrement de la macro ;
  • 1000@q exécute la macro q 1000 fois, à remplacer par ce qu’il te faut (tu peux dépasser).

En effet le mode visuel de Vim ne fonctionne que sur des trucs parfaitement alignés.

Ici, pour moi c’est du boulot pour :substitute. L’avantage, ce que l’on en fera sera compréhensible (adaptable à sed, etc).

:%s#<TAGA>\(.\{-}\)</TAGA>#function("\1")#

Avec:

  • \(...\) pour délimiter un groupe que l’on rappellera avec \1
  • . pour n’importe quel caractère
  • \{-} pour la répétition qui en prend le moins possible.

Note: j’ai employé .\{-} n’étant pas sûr que ton pattern soit vraiment Value\d\+

Pour gérer plusieurs tags, on peut aussi s’en sortir avec

:%s#<\(\k\+\)>\(.\{-}\)</\1>#function("\2")#

Juste comme ça. Je comprends mal la méthode à base de regex.

C’est pas plus simple à lire. C’est plus compliqué à écrire (je ne parle pas des quelques caractères en plus mais bien de penser à utiliser #, de gérer des groupes, échapper des caractères. D’ailleurs, j’ai du checker la doc pour comprendre \k que je ne connaissais pas. Je ne connaissais pas non plus \{-} d’ailleurs je sais pas où je peux trouver une doc, même si ça se comprends correctement.

J’ai également du mal à le traduire avec Sed.

La solution à base de macro Vim me semble plus “naturelle”.

+0 -0

En toute honnêteté, il y a beaucoup une question d’habitude. Pratiquant intensément vim depuis fort longtemps, je connais bien sa syntaxe de regex. Pour # (ou autre), on apprend vite à s’en servir dès que l’on a des slashs (typiquement pour des noms de fichiers), même avec sed. Pour la doc, c’est bien caché, tous les machins se trouvent avec slash+anti-slash

Après, la syntaxe avec sed est subtilement différente: pas de backslash pour les groupes, et je ne me souviens jamais de la syntaxe pour le * paresseux que j’utilise ici. Les habitués à la même chose avec perl (plus riche en regex) auront encore une autre syntaxe.

Ce que je n’aime pas avec les macros, c’est qu’il ne faut pas se planter quand on l’enregistre. Certes, je connais toute la syntaxe. Mais j’ai toujours un doigt qui rippe et appuie sur la mauvaise touche, un doute sur le nombre à injecter au Change Forward (ou Till) — que j’utilise donc en général de façon interactive en mode visuel. Du coup, je suis plus à l’aise avec :substitute que je programme que les macros qu’il faut saisir d’une traite sans se planter. (Pour la longueur, coté vimgolf, le C remplace avantageusement c$ ;))

Merci pour vos réponses! J’ai essayé les deux méthodes avec succès.

J’ai trouvé la méthode des macros un peu plus facile à mettre en place avec mon petit niveau. Mais j’ai pas été très efficace dans l’application de la macro. J’ai enchaîné les XX@a. Du coup question subsidiaire il y a un moyen de dire à vim d’appliquer une macro à chaque ligne jusqu’à une certaine ligne (définie avec un pattern par exemple?, peut être à partir une sélection visuel?).

Pour la méthode des patterns pour le coup c’est plus facile à appliquer à toutes les lignes concernées.

Merci :)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte