Vi and Vim Stack Exchange is a question and answer site for people using the vi and Vim families of text editors. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I've the following format of the file:

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

and I would like to delete everything what is between <inputs> and </inputs> (excluding pattern it-self) and replace it with the content from another file (e.g. foo.txt). In other words lines with foo=bar and bar=foo would be replaced with another content.

Probably it can be similar to how you delete a multi-line match, like:

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

but I'm not sure with what I should replace the d in order to insert the content of another file, but I want to keep the matching pattern.

Similar approach would be to remove inner content of html tag, like

:/<inputs>/norm vitd

but then I don't know how would you add into it the content from the file.

Ideally I'm trying to find one liner, since it'll be part of another script.

How can I achieve that?

share|improve this question
up vote 8 down vote accepted

A substitution can be used to replace a pattern with the result of an expression like this:

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

See :help sub-replace-expression

Note that keeppatterns prevents the substitute command from adding anything to the search history and preserves the "last search pattern register" - see :help "/. It's good practice to prevent scripts from unnecessarily modifying Vim's global state with the command modifiers keepalt, keepjumps, lockmarks, keepmarks, and keeppatterns.

share|improve this answer
    
QQ: What's the purpose of keeppatterns? – kenorb Feb 2 at 12:27

An alternative approach to that from Gary is this:

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

Which first deletes everything in the given pattern, than uses the :r command to read the data from file dummy. Now if you need to extract the filename from the lines between the <input>/</input> pattern, it gets a litte bit more complicated.

share|improve this answer

This seems to work, at least on a Unix system:

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

It uses the {range}!{filter} command to filter the lines from one after <inputs> to one before </inputs> through the external program cat foo.txt. In this case, cat ignores its standard input, so the original lines are deleted and replaced by the contents of the file foo.txt.

See:

:help :range!
:help cmdline-ranges
share|improve this answer

I feel a macro will be a easier approach. Especially, if you have various places to do the same.

  1. Keep only those 2 files open.
  2. Now in the first file start recording by qa, (a is the record name).
  3. Search for the start pattern, press down, then press Ctrl-v, search for the end pattern, press up. Now the part which you want to delete is selected. Delete it.
  4. Mark the position using ma (a is the mark name) and save the file.
  5. Go to the 2nd file, by :b2 command and similarly select the part as per your start/end criteria.
  6. Come back to this file press a to go to that point. Paste there by p.
  7. Search for end criteria again, and cross the section to not hit it again.
  8. Quit recoding by pressing q.
  9. Repeat the number of times by 40@a.
share|improve this answer
1  
Thanks for the suggestion, it's fine, but it won't help in this particular case, since I'm looking for non-interactive solution as part of ex script where I can specify which file to insert depending on the user input arguments. – kenorb Feb 2 at 12:35

If this is another attempt to parse XML with non-XML Tools, don't.

The solutions here are valid, but the intention might not be. If the XML is not from a well tamed source, you might get escapes, CDATA, or white spaces in the tag!

So xsltproc from command in vi can deal with that.

share|improve this answer
    
The file is not actually proper XML format, but it's actually not well documented ini file having those 3 XML-like tags. – kenorb Feb 2 at 12:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.