Search code examples
vimvi

using vim regex to prepend/append characters or strings before/after matched strings


Suppose you have a list like this:

file_exts = [tex~, log~, synctex.gz, aux, synctex, tuc, fls, log, fdb_latexmk, bcf, bbl, blg]

I want to surround each of the elements with a single quote. Is there a way to do it in Vim efficiently like this?:

file_exts = ['tex~', 'log~', 'synctex.gz', 'aux', 'synctex', 'tuc', 'fls', 'log', 'fdb_latexmk', 'bcf', 'bbl', 'blg']

The second case is as follows. If I want to append a string to the end of certain lines with strings matched but not replace the strings themselves, how would I do it? Here is an example

His name is Evan
His phonenumber is 333-444

I want to append say an ... to the end of the strings matched by /his.

His name is Evan...
His phonenumber is 333-444...

I know I can do this by line number but it is not possible in my use case.


Solution

  • For the first question. You may select content inside the [ ... ] (e.g. by typing vi[) and then execute the following command:

    :'<,'>s/\%V\([a-z~.]\+\)/'\1'/g
    

    Now I am going to explain each part of the command

    1. '<,'> is a range, it means that we want to apply the following command for selected lines only, not to the whole file. Usually vim inserts this automatically when you start command while in visual mode.
    2. Similarly \%V means here "restrict matching inside the visual area". The range from the 1. restricts matching only to selected lines, but not to selected characters. We need \%V to prevent applying the command to the file_exts word.
    3. s/pattern/replacement/ is just a substitusion command: it replaces the specified pattern with the specified replacement.
    4. [a-z~.]\+ is just a regular expression, which means "match a sequence of one or more characters from the list: a-z, ~ or .".
    5. We do not want to substitute, but modify existing items. So in the pattern part we save it with the \( ... ) construction to a (somewhat) register, and use it later as \1 in the replacement part. So the replacement part is just '\1'.
    6. By default vim applies substitution only once per line. We want to apply it multiple times, so we added the g flag at the end of the command.

    This is not the easiest way possible, but fairly straightforward and easily customizable for similar tasks.

    If you want more details for each of the topics, you may check out vim help:

    :help '<
    :help '>
    :help \%V
    :help pattern
    :help :s
    :help s/\1
    :help s_flags
    

    For the second question: besides the g/ solution mentioned in the comments, you may use :s as well:

    :'<,'>s/\(Evan\|444\)$/\1...