2

I deleted lines in a file with

:g/^\s*key3/d

and now have a file like this:

entry{entryname1,
    key1 = {text},
    key2 = {text},
}

entry{entryname2,
    anotherkey = {text},
    yetanotherkey = {text}
}
...

I want to delete the trailing comma after key2 (the name of the last key can change) on multiple lines in the file.

Is there a command (or multiple commands) that does the following:

for each line with the pattern ^}$:
  if the last character in the previous line is a comma:
    delete that comma

3 Answers 3

2

You can use :g again with a regular expression, but use a line offset of -1 to have the global command act on the lines above the match.

Then you can use that to apply a :s command to remove any trailing commas.

Putting it all together:

:g/^{$/-1s/,$//

These offsets are explained in section 10.3 of the Vim manual:

ADD AND SUBTRACT

There is a slight error in the above command: If the title of the next chapter had included "grey" it would be replaced as well. Maybe that's what you wanted, but what if you didn't? Then you can specify an offset.

To search for a pattern and then use the line above it:

/Chapter/-1

etc.

Documentation under :help cmdline-ranges has more advanced examples. Even though the discussion is mainly around ranges preceding a command, many of those expressions will work after :g as well.

3
  • 1
    Same answer, just took me longer to type! :)
    – D. Ben Knoble
    Mar 4, 2020 at 15:38
  • @D.BenKnoble Looks great to me! I actually took some time looking for references. This is an area where I think the docs are not very direct as they usually are, since :g takes a pattern but that usually behaves more like ranges do, with line offsets and ; to introduce a second pattern (I believe those work too.)
    – filbranden
    Mar 4, 2020 at 15:43
  • 1
    yeah :g is one of the more powerful commands, but deciphering it can be hard! The trick I always use is that global defines a set of lines to operator over, a bit like for line matching /pat/, execute cmd with the current line as $line (kind of like Awk)—then, adding a range to cmd makes perfect sense; it starts from $line if it's relative or pattern-based.
    – D. Ben Knoble
    Mar 4, 2020 at 15:50
3

I can think of a number of ways to make this work:

First would be only the key2 case:

global/key2/substitute/,$//

Now, in the general case, I believe you want to do

global/^}$/-substitute/,$//

:global can be abbreviated to :g and :substitute to :s. - in the range here is equivalent to -1, as explained at :help [range].

There's one other way to note: :g/^}$/-normal! 0f,x should work if there's only one comma in the lines you want to modify, and none in the lines you want to leave alone—this works because normal! will stop if any of the given commands fail. Since f, will fail when there's no comma, x will never be executed.

2

I interpret your question thus: wherever in the file you have comma followed by new-line that contains only }, delete all such commas.

:%s/,\n}$/\r}/

\n in the pattern identifies a line break, \r in replacement inserts a line break. I've no idea why they should be different.

1
  • 1
    Thanks for pointing that out. I often have to do an edit over because I'm too hasty to check it the 1st time.
    – user985675
    Mar 6, 2020 at 20:17

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.