Як замінити вміст між двома шаблонами з файлу?


9

У мене такий формат файлу:

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

і я хотів би видалити все, що знаходиться між <inputs>і </inputs>(за винятком шаблону самостійно) та замінити його вмістом з іншого файлу (наприклад foo.txt). Іншими словами, рядки з foo=barта bar=fooбудуть замінені іншим змістом.

Можливо, це може бути схожим на те, як ви видаляєте багаторядкові збіги , наприклад:

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

але я не впевнений, чим би я міг замінити d, щоб вставити вміст іншого файлу, але я хочу зберегти відповідність.

Аналогічний підхід був би для видалення внутрішнього вмісту тегів html , наприклад

:/<inputs>/norm vitd

але тоді я не знаю, як би ви додали до нього вміст із файлу.

В ідеалі я намагаюся знайти один лайнер, оскільки це буде частиною іншого сценарію.

Як я можу цього досягти?

Відповіді:


10

Заміна може бути використана для заміни шаблону з результатом такого виразу:

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

Подивитися :help sub-replace-expression

Зверніть увагу, що keeppatternsзаважає substituteкоманді нічого не додавати до історії пошуку та зберігає "останній реєстр шаблонів пошуку" - див :help "/. Це хороша практика , щоб запобігти сценарії від надмірно зміни глобального стану Vim з командними модифікаторів keepalt, keepjumps, lockmarks, keepmarks, і keeppatterns.


5

Альтернативний підхід до Гері полягає в наступному:

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

Котрий спочатку видаляє все у заданому шаблоні, ніж використовує :rкоманду для зчитування даних з фіктивного файлу. Тепер, якщо вам потрібно витягнути ім'я файлу з рядків між <input>/</input>шаблоном, це стає трохи більш складним.


4

Це, здається, працює, принаймні, в системі Unix:

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

Він використовує {range}!{filter}команду для фільтрації рядків від одного <inputs>до одного раніше </inputs>за допомогою зовнішньої програми cat foo.txt. У цьому випадку catігнорується його стандартний вхід, тому початкові рядки видаляються та замінюються вмістом файлу foo.txt.

Подивитися:

:help :range!
:help cmdline-ranges

2

Я думаю, що макрос буде простішим підходом. Тим більше, якщо у вас є різні місця, щоб зробити те саме.

  1. Тримайте відкриті лише ці 2 файли.
  2. Тепер у першому файлі почати запис із qa,( aце назва запису).
  3. Пошук за шаблоном запуску, натисніть вниз , а потім натисніть Ctrl- v, пошук кінцевої моделі, натисніть вгору . Тепер вибрана частина, яку ви хочете видалити. Видаліть його.
  4. Позначте позицію за допомогою ma( aце ім'я марки) та збережіть файл.
  5. Перейдіть до другого файлу за :b2командою та аналогічно виберіть частину відповідно до критеріїв початку та кінця.
  6. Поверніться до цього файлу, натисніть, aщоб перейти до цього пункту. Вставте туди p.
  7. Повторіть пошук кінцевих критеріїв та перекресліть розділ, щоб не повторити його.
  8. Вийдіть із перекодування, натиснувши q.
  9. Повторіть кількість разів 40@a.

1
Дякую за пропозицію, це добре, але це не допоможе в цьому конкретному випадку, оскільки я шукаю неінтерактивне рішення як частину exскрипту, де можу вказати, який файл вставити залежно від аргументів введення користувача.
kenorb

1

Якщо це ще одна спроба розбору XML з інструментами, які не є XML, не робіть.

Рішення тут справедливі, але наміру це може бути не так. Якщо XML не є добре прирученим джерелом, у тегу можуть з’явитися втечі, CDATA або пробіли!

Тож xsltproc з команди in vi може з цим впоратися.


Файл насправді не є належним форматом XML, але насправді він не є добре задокументованим iniфайлом, який має ці 3 теги, схожі на XML.
kenorb
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.