Search and replace in multiple lines in VIM

Vim_logoSo.. I had this issue where I have to replace stuff in the code where the text is splitted across several lines, this is basically because the string is too long and we usually keep the 80 characters width in the code (PEP-8) but this also works in HTML where for example, comments are splitted across several lines.

Let’s say that I want to remove the call to a function that process a text, the most common function that process text is the one everyone uses for translations: _(). The easy way is just to try a simple search and replace in vim:

:%s/_(\(.\{-}\))/\1/gc

Which will replace search for something like _("Translate this") and will leave it like this: "Translate this".  the :%s  part indicates that we want to search across the whole file, / is the delimiter, there are three delimiters, the pattern, the replacement and operation flags. Since we want to match _(.*) but we want to preserve what’s inside the parenthesis we need to create a backreference and we need to surround that between \( and \). The dot . matches every character except new lines. Please note that we use \{-} instead of the most common * (asterisk) for “one or more” occurrences.  This is because \{-} will match as few as possible, while * is too greedy and will stop at the last occurrence. Then we set the replacement string, we wanted to leave the string intact so we just use the backreference: \1 is the first backreference, \2 for the second and so on. The last gc are there just to ask you for every match, but you can just press “a” to apply to everyone.

If you want to search/replace multiple lines, then you can just use the \_. pattern in vim, that pattern matches every character including new lines.

:%s/_(\(\_.\{-}\))/\1/gc

 

So, for example:

_("This is a text"
" That is splitted across"
" several lines").upper()

after :%s/_(\(\_.\{-}\))/\1/gc will be

"This is a text"
" That is splitted across"
" several lines".upper()

 3,930 total views,  1 views today