Comment remplacer le contenu entre deux modèles du fichier?

9

J'ai le format de fichier suivant:

<common>
fitnes=0
genetic=1
method=0
</common>
<inputs>
foo=bar
bar=foo
</inputs>
<limits>
balance=200.00
</limits>

et je voudrais supprimer tout ce qui est entre <inputs>et </inputs>(à l'exception du motif lui-même) et le remplacer par le contenu d'un autre fichier (par exemple foo.txt). En d'autres termes, les lignes avec foo=baret bar=fooseraient remplacées par un autre contenu.

Cela peut probablement être similaire à la façon dont vous supprimez une correspondance sur plusieurs lignes , comme:

:g/<inputs/,/inputs>/d

mais je ne suis pas sûr de ce que je devrais remplacer dpour insérer le contenu d'un autre fichier, mais je veux garder le modèle correspondant.

Une approche similaire consisterait à supprimer le contenu interne de la balise html , comme

:/<inputs>/norm vitd

mais je ne sais pas comment y ajouter le contenu du fichier.

Idéalement, j'essaie de trouver un liner, car il fera partie d'un autre script.

Comment puis-je y parvenir?

Kenorb
la source

Réponses:

10

Une substitution peut être utilisée pour remplacer un motif par le résultat d'une expression comme celle-ci:

:keeppatterns %s;<inputs>\zs\_.\{-}\ze</inputs>;\=insert(readfile('test.txt'), '')

Voir :help sub-replace-expression

Notez que cela keeppatternsempêche la substitutecommande d'ajouter quoi que ce soit à l'historique de recherche et préserve le "dernier registre de modèle de recherche" - voir :help "/. Il est une bonne pratique pour éviter les scripts de modification inutilement état global de Vim avec les modificateurs de commande keepalt, keepjumps, lockmarks, keepmarks, et keeppatterns.

djjcast
la source
5

Une approche alternative à celle de Gary est la suivante:

:g/^<inputs>/+,/^<\/inputs>/-d|-r dummy

Ce qui supprime d'abord tout dans le modèle donné, puis utilise la :rcommande pour lire les données du fichier factice. Maintenant, si vous avez besoin d'extraire le nom de fichier des lignes entre le <input>/</input>motif, cela devient un peu plus compliqué.

Christian Brabandt
la source
4

Cela semble fonctionner, au moins sur un système Unix:

:/<inputs>/+1,/<\/inputs>/-1!cat foo.txt

Il utilise la {range}!{filter}commande pour filtrer les lignes l'une après l' <inputs>autre avant </inputs>via le programme externe cat foo.txt. Dans ce cas, catignore son entrée standard, les lignes d'origine sont donc supprimées et remplacées par le contenu du fichier foo.txt.

Voir:

:help :range!
:help cmdline-ranges
garyjohn
la source
2

Je pense qu'une macro sera une approche plus facile. Surtout, si vous avez plusieurs endroits pour faire de même.

  1. Ne gardez que ces 2 fichiers ouverts.
  2. Maintenant, dans le premier fichier, commencez l'enregistrement par qa,( aest le nom de l'enregistrement).
  3. Recherchez le motif de début, appuyez vers le bas , puis appuyez sur Ctrl- v, recherchez le motif de fin, appuyez vers le haut . Maintenant, la partie que vous souhaitez supprimer est sélectionnée. Supprime-le.
  4. Marquez la position en utilisant ma( aest le nom de la marque) et enregistrez le fichier.
  5. Accédez au 2ème fichier, par :b2commande et sélectionnez de la même manière la pièce selon vos critères de début / fin.
  6. Revenez à ce dossier en appuyant sur apour aller à ce point. Collez-le par p.
  7. Recherchez à nouveau les critères de fin et traversez la section pour ne plus y toucher.
  8. Quittez le recodage en appuyant sur q.
  9. Répétez le nombre de fois par 40@a.
Krishanu Banerjee
la source
1
Merci pour la suggestion, c'est bien, mais cela n'aidera pas dans ce cas particulier, car je recherche une solution non interactive dans le cadre d'un exscript où je peux spécifier le fichier à insérer en fonction des arguments d'entrée de l'utilisateur.
kenorb
1

S'il s'agit d'une nouvelle tentative d'analyse XML avec des outils non XML, ne le faites pas.

Les solutions ici sont valables, mais l'intention pourrait ne pas l'être. Si le XML ne provient pas d'une source bien apprivoisée, vous pourriez obtenir des échappements, CDATA ou des espaces blancs dans la balise!

Donc xsltproc de la commande dans vi peut gérer cela.

Matthias Š
la source
Le fichier n'est pas réellement le format XML correct, mais ce n'est en fait pas un inifichier bien documenté ayant ces 3 balises de type XML.
kenorb