Как заменить содержимое между двумя шаблонами из файла?

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

но тогда я не знаю, как бы вы добавили в него содержимое из файла.

В идеале я пытаюсь найти один лайнер, так как он будет частью другого скрипта.

Как я могу этого достичь?

kenorb
источник

Ответы:

10

Подстановка может использоваться для замены шаблона результатом выражения, подобного этому:

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

Видеть :help sub-replace-expression

Обратите внимание , что keeppatternsпрепятствует тому , чтобы substituteкоманда добавлять ничего к истории поиска и заповедникам «последний шаблон поиск регистр» - см :help "/. Это хорошая практика , чтобы предотвратить сценарии от излишне изменения глобального состояния Vim с командными модификаторов keepalt, keepjumps, lockmarks, keepmarks, и keeppatterns.

djjcast
источник
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
garyjohn
источник
2

Я чувствую, что макрос будет более легким подходом. Особенно, если у вас есть разные места, чтобы сделать то же самое.

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

Если это еще одна попытка синтаксического анализа XML с помощью инструментов, отличных от XML, не делайте этого.

Решения здесь действительны, но намерение не может быть. Если XML не из хорошо прирученного источника, в теге могут быть экранированные символы, CDATA или пробелы!

Таким образом, xsltproc из команды в vi может справиться с этим.

Матиас Ш
источник
Файл на самом деле не является правильным XML-форматом, но на самом деле это не очень хорошо документированный iniфайл, имеющий эти 3 XML-подобных тега.
Кенорб