Multiple possible find-replace in Gvim - vim

I want to create a command or function to combine multiple finds and replaces. I have tried following command:
command MyFR %s/first/1st/g | %s/second/2nd/g | %s/third/3rd/g
It works but stops midway if no 'first' or 'second' is found. The error is:
E486: Pattern not found: <pattern>
How can I make this command work for 'second' and 'third' to be replaced, even if there is no 'first' in text? Thanks for your help.

You could add the e flag to each of your substitution command, which is described in :h :s_flags:
[e] When the search pattern fails, do not issue an error message and, in
particular, continue in maps as if no error occurred. This is most
useful to prevent the "No match" error from breaking a mapping. Vim
does not suppress the following error messages, however:
Regular expressions can't be delimited by letters
\ should be followed by /, ? or &
No previous substitute regular expression
Trailing characters
Interrupted
It would give:
com! MyFR %s/first/1st/ge | %s/second/2nd/ge | %s/third/3rd/ge
Another solution would be to merge all substitutions into a single one:
com! MyFR %s/\vfirst|second|third/\={'first': '1st', 'second': '2nd', 'third': '3rd'}[tolower(submatch(0))]/g
This time, in the replacement part, instead of using a literal string, you would use an expression (see :h s/\=). Here, the expression is a given value of a dictionary.
The keys of the dictionary are all your possible matched texts, and the values are their replacements.
The value you retrieve from the dictionary is tolower(submatch(0)) which evaluates into the matched text (see :h submatch()), normalized in its lowercase version (all uppercase characters are turned into their lowercase counterpart through tolower()).

Related

how to remove specific characters in vi or vim editor

I have some txt in vi:
|NC_004718|29751nt|SARS
|NC_045512|29903nt|Severe
|NC_004718|29751nt|SARS
|NC_045512|29903nt|Severe
|NC_004718|29751nt|SARS
now I want to replace remove everything after NC_004718, my expected output is:
NC_004718
NC_045512
NC_004718
NC_045512
NC_004718
How to do it? Thanks.
I would recommend using a substitution with regular expression to match the entire string and to capture what you would like to keep in parentheses. That way you can then replace the entire string with just the match.
:%s/^|\([^|]\+\)|.\+/\1/
To break down what is happening:
% means that you want to apply the command to each line within the file.
s means that you are doing substitution command (on each line). The s command has a syntax of s/<regular expression pattern>/<replacement>/<flags>
The regular eression pattern in the above command is ^|\([^|]\+\)|.\+.
^ means match from the line start.
| matches the character |.
\([^|]\+\) matches all characters except for the character |. Note that the real regular expression is actually ([^|]+), the additional \ characters are there because Vim needs to know that they are intended to be special characters for processing and not exact characters it needs to match. Also note that the parentheses are there to capture the match into a group (see below).
| again matches the actual character |.
.\+ matches all characters until the end of the line. Note that the . is considered special character by default but + still needs a preceding \.
The replacement text is only \1. This denotes that Vim should replace the text with whatever was captured in the first group (i.e. the first set of parentheses).
There are no flags with this command so there is nothing after the last /.
For example,
:g/NC_\d\+/normal! ygnV]p
:g/regex/ to match lines
normal! to execute Normal mode commands
ygn to yank the text previously matched by :g
V to select the whole line
]p or p to replace the line with the match
If you have only lines like those you have shown try:
:%norm xf|D

Search and replace all characters past the first occurrence of space in each line in Vim?

I have some text in the following format:
column1 DATE,
column2 VARCHAR2(6),
column3 VARCHAR2(15)
(It is the format of Oracle column definitions in case you are wondering.)
I’ve been trying to figure out how to replace everything past the space in each line with VARCHAR2(255),, but haven’t been successful yet.
I know I can search the occurrences of space via /\s, but I can’t figure out how to get the rest of the string on the line. When I use /\s*, it highlights all the text. I attempted to use /\s.+, but I get a “Pattern not found” error.
How can I get all text past the space in each line and replace it globally with another string?
Easiest way:
:%s/ .*/ VARCHAR(255)
VIM uses a slightly weird regex syntax so if you wanted to do \s+ you'd have to use \s\+
How about
:%s/\s\S\+$/ VARCHAR(255)/
As an alternative to using substitution commands (which have already
been proposed in other answers), one can repeat a sequence of
Normal-mode commands on every line using the :normal Ex command:
:%norm!f C VARCHAR(255)
One way:
:%s/\(\s\+\).*$/\1VARCHAR(255)/
For every line (%), find the first run of whitespace characters (\(\s\+\)), save them in match group 1 (to be referenced as \1 in the replacement string), match the rest of the line (.*$), and replace it with the desired literal string.
(You must escape the + character in the regexp in magic mode. You can use the very magic mode with \v at the beginning of the regexp. See :help magic for details.)

How to do substitution only on highlighted text in vim?

Before doing substitution, I usually type /foo to search the pattern first.
Vim automatically highlight all strings match the pattern.
Then I figure out how to write the substitution command :%s/foo/bar/g.
When the pattern is complex, it's much harder to write the substitution command than the search command.
If I can do substitution only on highlighted strings. It becomes easy.
For example:
Question: Translate Part of a Line
I can figure out the search pattern: /\[\[\(http\)\#!.\{-}\]\]
But I cannot figure out the substitution command easily.
You can replace the previously searched pattern if you use an empty string as the search pattern in the substitute command:
After /foo type :%s//bar/g in normal mode to replace "foo" by "bar".
You could use the 'c' flag to tell Vim to confirm before replacing. It highlights and stops to ask before every match it finds to the given pattern.
:%s/foo/bar/gc
I just figured out:
:%s##\=substitute(submatch(0), '_', '/', '')#g
But is there any better ways?

pattern found in vim search, but not in vim search and replace?

There is a search and replace operation I am trying to do using backreferencing and regular expressions in vim. Interestingly, it will only recognize the pattern if I do a pure search, but if I do a search and replace it gives me an E486: pattern not found error.
I have a bunch of function calls of the form:
function( Nullable< double >(1.1), map[FOO] );
Where FOO is some different variable name on each line. I want to turn it into
function( othermap[ FOO ], map[FOO] );
If I try
:%s/Null.*\(map[\)\(.*\)\]/othermap[ \2 \], \1\2\]/g
It gives me the "Pattern not found error." Even
:%s/Null.*\(map[\)\(.*\)\]//g
will not work because it's just not recognizing the pattern. But if I try the following command with the exact same search regex:
/Null.*\(map[\)\(.*\)\]
It highlights correctly. Following which, I can do %s//othermap[ \2 ], \1\2] to do my replacement. So I was able to do my replacement after all, but I can't for the life of me understand why the pattern would be recognized in one case and not in the other.
I can reproduce the result using copy'n'paste from your question to my vim session. The detailed message I get, though, is:
E486: Pattern not found: Null.*\(map[\)\(.*\)\]/othermap[ \2 \], \1\2\]/g
Note that it has lost the s/ at the start.
However, looking rather carefully at this, the trouble is an unescaped [:
s/Null.*\(map[\)\(.*\)\]/othermap[ \2 \], \1\2\]/g
^
|-- here; you need \[ to match the literal
I don't use the % notation; I would automatically write:
:g/Null.*\(map\[\(.*\)\]\)/s//othermap[\2], \1/g
This has slightly different capturing. There was also no need to use the backslash in \] in the replacement string.
However, this command also works for me:
:%s/Null.*\(map\[\(.*\)\]\)/othermap[\2], \1/g

Multiple search and replace in one line

If I do something like:
:%s/aaa/bbb/ | %s/111/222/
and the first search and replace doesn't find any matches, the second search and replace won't be executed. Is there any way to tell vim to carry on even when a command "failed"?
Try
:%s/aaa/bbb/e | %s/111/222/e
and read
:help :s_flags
especially the entry under [e]:
When the search pattern fails, do not issue an error message and, in
particular, continue in maps as if no error occurred. This is most
useful to prevent the "No match" error from breaking a mapping. Vim
does not suppress the following error messages, however:
Regular expressions can't be delimited by letters
\ should be followed by /, ? or &
No previous substitute regular expression
Trailing characters
Interrupted

Resources