Yesterday I tried to substitute all ( ) in my text but not the one found in matches from a previous search. I couldn't find a good solution. I did it changing one by one.
This is my original text:
(Peter Jackson) is the man who..... (John Johnson) is the man who....
and (John Johnson) is also the man who.. not as (Jon Johnson)
more (letters) etc.
My search pattern: /(\a*\sJohnson)
How can I substitute all ( ) characters in the text to [ ], but not the one found in matches?
The result should be:
[Peter Jackson] is the man who..... (John Johnson) is the man who....
and (John Johnson) is also the man who.. not as (Jon Johnson)
more [letters] etc.
Edit
Is there an easy method to substitute one or more whatever characters in a text but not these in matches?
You can use \#!(Negative Lookahead):
:%s/(\%(\a*\sJohnson\)\#!\([^)]*\))/[\1]/g
->|............|<---
\%(...\)\#! is a Negative Lookahead.
\([^)]*\) will match everything except ).
I use \%( to ignore a captured group, otherwise you need /[\2]/
This can work:
:%s/(\(\a*\sJohnson\))/LEFTPARENT\1RIGHTPARENT/g
:%s/(/[/g
:%s/)/]/g
:%s/LEFTPARENT/(/g
:%s/RIGHTPARENT/)/g
One can use the following substitution command to achieve the purpose in
question.
:%s/(\(.\{-}\%(IGNORE.\{-}\)\#<!\))/[\1]/g
where IGNORE designates the pattern that does not match in parentheses that
are to change (\a*\sJohnson, for instance).
In order to solve a general problem of substituting everywhere in buffer
except in the matches of IGNORE pattern, one can use the command
:%s/\(IGNORE\)\zs\|s/\=submatch(1)!=''?'':'t'/g
Related
I have a data file (comma separated) that has a lot of NAs (It was generated by R). I opened the file in vim and tried to replace all the NA values to empty strings.
Here is a sample slimmed down version of a record in the file:
1,1,NA,NA,NA,NATIONAL,NA,1,NANA,1,AMERICANA,1
Once I am done with the search-replace, the intended output should be:
1,1,,,,NATIONAL,,1,NANA,1,AMERICANA,1
In other words, all the NAs should be replaced except the words NATIONAL, NANA and AMERICANA.
I used the following command in vim to do this:
1, $ s/\,NA\,/\,\,/g
But, it doesn't seem to work. Here is the output that I get:
1,1,,NA,,NATIONAL,,1,NANA,1,AMERICANA,1
As you can see, there is one ,NA, that is left out of the replacement process.
Does anyone have a good way to fix it? Thanks.
A trivial solution is to run the same command again and it will take care of the remaining ,NA,. However, it is not a feasible solution because my actual data file has 100s of columns and 500K+ rows each with a variable number of NAs.
, doesn't have a special meaning so you don't have to escape it:
:1,$s/,NA,/,,/g
Which doesn't solve your problem.
You can use % as a shorthand for 1,$:
:%s/,NA,/,,/g
Which doesn't solve your problem either.
The best way to match all those NA words to the exclusion of other words containing NA would be to use word boundaries:
:%s/,\<NA\>,/,,/g
Which still doesn't solve your problem.
Which makes those commas, that you used to restrict the match to NA and that are causing the error, useless:
:%s/\<NA\>//g
See :help :range and :help \<.
Use % instead of 1,$ (% means "the buffer" aka the whole file).
You don't need \,. , works fine.
Vim finds discrete, non-overlapping matches. so in ,NA,NA,NA, it only finds the first ,NA, and third ,NA, as the middle one doesn't have its own separate surrounding ,. We can modify the match to not include certain characters of our regex with \zs (start) and \ze (end). These modify our regex to find matches that are surrounded by other characters, but our matches don't actually include them, so we can match all the NA in ,NA,NA,NA,.
TL;DR: %s/,\zsNA\ze,//g
Is it possible to replace a section in the searched result? for example I have currently
<stringProp name="Argument.name">revision_no</stringProp>
<stringProp name="Argument.value">1</stringProp>
I want to replace the number (1) with ${var} on the 2nd line, and all other information remains the same.
If I type
:%s/revision_no<.*\n.*value">[0-9]\*/revision_no<(all the characters...) value">${var}/g
I might lose all the format(indentation involved)..
So I am wondering if there is a way to just replace "1" with ${var} in the whole search result.
`
You can capture the other matching text (that you want to keep), and then reference that exact text in the replacement. The \(...\) is a capture group (:help /\(), and \1 references it (the first such group) in the replacement. This is the traditional way, and it also works in sed and many other regular expression-based tools:
:%s/\(revision_no<.*\n.*value">\)[0-9]\+/\1${var}/g
Alternatively, in Vim, you can assert that certain surrounding stuff matches without actually including it in the match. This "cutting" is done via \zs (start match here) and \ze (end match here):
:%s/revision_no<.*\n.*value">\zs[0-9]\+/${var}/g
I was wondering how I might go about moving around Columns/Text around in VIM using a string. I have a short list of names I have to reorder, which need to be placed in Last Name First Middle to First Middle Last.
So here would be an example list:
Plant, Robert A.
Page, Jimmy
Bonhham, John H.
Jones, John Paul
I was thinking that the string should look something like this:
:s/\([A-z]\{2}\)\(\[A-z]\{2}\)/2\1/
Thanks
First, I recommend using the \v "very magic" flag to avoid all the other internal escaping of metacharacters. This will work with a replacement like:
:s/\v([A-z]+),\s+([A-z]+)(\s+[A-z.]+)?/\2\3 \1
Breaking it down:
([A-z]+) Capture the last name into \1
,\s+ A literal comma and one or more spaces
([A-z]+) Capture the first name into \2
(\s+[A-z.]+)? Capture the middle name with its leading spaces, since it may not exist. Also permit the ., and end with a ? to make the whole construct optional, into \3
\2\3 \1 Replace with the second group (first name) followed immediately by the middle name \3 with no space in between because the space was captured along with the middle name. Then append \1 the last name.
If the names could be possibly more than [A-z]+, you may alternatively use [\S]+ to capture all non-whitespace characters.
How about this:
:%s/\([[:alpha:]]\+\), \([[:alpha:]]\+\)\( [[:alpha:]]\+\.\?\)\?/\2\3 \1/g
This captures last, middle (optional), and first, and reorders them in the replacement. You'll probably need to include additional characters in the [[:alpha:]] collection, but this works for your example.
For more information, learn how the excellent and comprehensive :help is structured; all the information is in there (you just need to know how to find it)! There are also many very similar regular expression questions here on Stack Overflow.
I am a beginner at Vim and I've been reading about substitution but I haven't found an answer to this question.
Let's say I have some numbers in a file like so:
1
2
3
And I want to get:
(1)
(2)
(3)
I think the command should resemble something like :s:\d\+:........ Also, what's the difference between :s/foo/bar and :s:foo:bar ?
Thanks
Here is an alternative, slightly less verbose, solution:
:%s/^\d\+/(&)
Explanation:
^ anchors the pattern to the beginning of the line
\d is the atom that covers 0123456789
\+ matches one or more of the preceding item
& is a shorthand for \0, the whole match
Let me address those in reverse.
First: there's no difference between :s/foo/bar and :s:foo:bar; whatever delimiter you use after the s, vim will expect you to use from then on. This can be nice if you have a substitution involving lots of slashes, for instance.
For the first: to do this to the first number on the current line (assuming no commas, decimal places, etc), you could do
:s:\(\d\+\):(\1)
The \(...\) doesn't change what is matched - rather, it tells vim to remember whatever matched what is inside, and store it. The first \(...\) is stored in \1, the second in \2, etc. So, when you do the replacement, you can reference \1 to get the number back.
If you want to change ALL numbers on the current line, change it to
:s:\(\d\+\):(\1):g
If you want to change ALL numbers on ALL lines, change it to
:%s:\(\d\+\):(\1):g
You can do what you want with:
:%s/\([0-9]\)/(\1)/
%s means global search and replace, that is do the search/replace for every line in the file. the \( \) defines a group, which in turn is referenced by \1. So the above search and replace, finds all lines with a single digit ([0-9]), and replaces it with the matched digit surrounded by parentheses.
I always wanted to know, how you can substitute within given parameters.
If you have a line like this:
123,Hello,World,(I am, here), unknown
and you wnat to replace World with Foobar then this is an easy task: :%s/World/Foobar/
Now I wonder how I can get rid of a , which is wihtin the ( ).
Theoretically I just have to find the first occurance of ( then substitute the , with a blank until ).
Try lookahead and lookbehind assertions:
%s/([^)]*\zs,\ze.*)//
(\zs and \ze tell where pattern starts and end)
or
%s/\(([^)]*\)\#<=,\(.*)\)\#=//
The first one is more readable, the second one uses \( ... \) groupings with parentheses inside groups which makes it look like obfuscated, and \#<= which apart from being a nice ASCII-art duck is the lookbehind operator, and \#= that is the lookahead operator.
References: :help pattern (more detail at :help /\#=, :help /\ze, etc.)
You use the GUI and want to try those commands? Copy them into the clipboard and run :#+ inside Gvim.
Modifying slightly the answer of #Tom can give you a quite good and "a bit" more readable result :
%s/\(.*\)(\(.*\),\(.*\))\(.*\)/\1(\2\3)\4/
That way you will have : in \1 will store what is at the left outside of the parenthesis, \4 what is at the right outside of the parenthesis and \2 and \3 what is inside the parenthesis, respectively on the left (\2) and on the right (\3).
With that you can easily swap your elements if your file is organised as column.
You can also select the text you want to change (either with visual or visual-block modes) and enter the : to start the replace command. vi will automatically start the command with :'<,'> which applies the command to the selected area.
Replacing a , can be done with:
:'<,'>s/,/ /g
For your example, this is the same thing as suggested by #ubuntuguy
%s/\(.*\)(\(.*\),\(.*\)/\1(\2\3
This will do the exact replacement you want.
Yet another approach, based on the fact that actually you want to substitute only the first occurrence of , inside the parenthesis:
:%s#\((.\{-}\),#\1 #
Explanation:
:%s for substitution in the whole file (don't use % if you want to work only with the current line)
we can use # or : as a delimiter to make the command more readable
in (.\{-} we ask to find any symbol (dot) after the left parenthesis and the rest stands for 0 or more occurrence (as few as possible) of this symbol. This expression is put inside \(...\) to be able to refer to this group as \1 in the future.