3

I'm trying to search for the string /c in the entire file, and when it's found I'd like to delete everything - including the /c itself - up until the next occurrence of / (but not the / itself). For the purposes I'm using this for, you can assume that:

  1. not every line will have a /c in it,
  2. but when there is one in a line, it will always be the only one in that line, and
  3. there will always be a / following it at some point in that same line.

I've learned of macros recently, and I found that if I create a macro with qa/\/c<CR>dt/q and then run it a large number of times with :g//normal 500@a, that it will make all the desired deletions (until it gets to the end of the file when it gives the error E486: Pattern not found: \/c). But I was wondering if there is a simpler way to do it - with some kind of :%s search command - that requires only one line. I'm quite certain there is, I just don't know how to do it. Alternatively, if a command or function could be created in the _vimrc file that would accomplish this task, that would work too.

2 Answers 2

3

I think the following command should do what you need:

:g:/c:s:/c[^/]*/:/:

Breaking it up:

  • :g: for every line that satisfies the condition
    • that it match /c (note, I'm using : as the regex delimiter for convenience, or I'd have to escape each / that I use)
  • run s:/c[^/]*/:/:, which:
    • looks for /c, followed by any number of non-/ characters and then a /, and
    • replaces it with a /. In effect, it leaves one / in place of the matched text, which includes both the boundary /.

Of course, you could have used your macro and run:

:g:/c:normal @a

The trick is to only run on those lines which match your condition.

2
  • 1
    Okay, I was a bit confused at first with all the : 's but your note reminded me that it could be used in place of / in order to avoid having to make all the other / 's into \/ 's. And I didn't know how to run the macro only on the lines that matched the condition. Thank you, @muru for the explanation. (Also, in my original question which I saw you edited, I thought that it was only "code" that should be put in the grey text box, so that's why I used quotes to refer to the /c pattern and the / character, but I'll remember to put these things in the grey text in the future.) Feb 20, 2016 at 10:39
  • 1
    @ablewasiereisawelba it's important to note that even quotes could be meaningful - what happens if you needed to match "foo bar", or use a register via "a? Use code formatting for things that should displayed exactly as meant to be used.
    – muru
    Feb 20, 2016 at 10:48
4

I'm not sure what is the difficulty:

:%s:/c.*\ze/::

or

:%s:/c.*/:/:

This searches in the whole file for /c followed at some point by / on the same line and:

  • either replaces the pattern, excluding the final /, with nothing (1st form)

  • or, the whole pattern is replaced by a single / (2nd form)

In order to avoid escaping / I simply used a different substitute separator (:). .* means "any number of unspecified characters, but only in the same line".

If more than one /c.*/ construct per line is possible, simply add g at the end to replace them all.

Note: the above match is greedy (matches until the last / on the line, "swallowing" all others into the pattern). For a non-greedy match, use [^/]* instead of .*. There is also .*\{-}, but it may not work with the 1st solution (before \ze/).

5
  • 1
    OP says "up until the next occurrence of /", so use non-greedy matching or [^/]* instead of .*.
    – muru
    Feb 20, 2016 at 10:02
  • Indeed, duly noted :)
    – VanLaser
    Feb 20, 2016 at 10:05
  • I found that @VanLaser 's initial solution had deleted the / as well, but his edited answer now works like I want it to. Thanks for the answer and explanation. Feb 20, 2016 at 10:09
  • Yes, I often find myself going for the solution when I got the main part, but not all the details.
    – VanLaser
    Feb 20, 2016 at 10:12
  • Oh, I didn't notice the part about "greedy" versus "non-greedy", because in my file, the next / is always the last / in each line. When I realized what that was referring to, I put an extra / at the end of the first line just to test it out, and saw that it was deleting everything up to the end of the line. Also, replacing .* with .*\{-} doesn't seem to work for either solution. Feb 20, 2016 at 10:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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