I would like to replace spaces with underscores inside quotes in part of a pattern.
Example input:
select
"AA" as "Long descriptive name",
"BB" as "Another long name",
"CC" as "There are many spaces here"
from
sometable;
Wanted output:
select
"AA" as "Long_descriptive_name",
"BB" as "Another_long_name",
"CC" as "There_are_many_spaces_here"
from
sometable;
I have tried doing this with the substitute() and submatch() functions like this but I can't get it to quite work (The \= part is not interpreted the substitute command is written into the file). Something is missing.
:%s/ as "\(.*\)"/ as \=substitute(submatch(1),' ', '_', 'g')/g
well you were close:
:%s/ as "\zs\(.*\)\ze"/\=substitute(submatch(1),' ', '_', 'g')/g
\= only is interpreted as expression if the string starts with it. see :h sub-replace-special. You can solve that problem by just matching the part you want to replace (using \zs and \ze in my example).
This does of course not always work. Then you will have to build a string again in the \= part. Which would look like that:
:%s/ as "\(.*\)"/\=' as "'.substitute(submatch(1),' ', '_', 'g').'"'/g
Related
I would like to use vim's substitute function (:%s) to search and replace a certain pattern of code. For example if I have code similar to the following:
if(!foo)
I would like to replace it with:
if(foo == NULL)
However, foo is just an example. The variable name can be anything.
This is what I came up with for my vim command:
:%s/if(!.*)/if(.* == NULL)/gc
It searches the statements correctly, but it tries to replace it with ".*" instead of the variable that's there (i.e "foo"). Is there a way to do what I am asking with vim?
If not, is there any other editor/tools I can use to help me with modifications like these?
Thanks in advance!
You need to use capture grouping and backreferencing in order to achieve that:
Pattern String sub. flags
|---------| |------------| |-|
:%s/if(!\(.*\))/if(\1 == NULL)/gc
|---| |--|
| ^
|________|
The matched string in pattern will be exactly repeated in string substitution
:help /\(
\(\) A pattern enclosed by escaped parentheses. /\(/\(\) /\)
E.g., "\(^a\)" matches 'a' at the start of a line.
E51 E54 E55 E872 E873
\1 Matches the same string that was matched by /\1 E65
the first sub-expression in \( and \). {not in Vi}
Example: "\([a-z]\).\1" matches "ata", "ehe", "tot", etc.
\2 Like "\1", but uses second sub-expression, /\2
... /\3
\9 Like "\1", but uses ninth sub-expression. /\9
Note: The numbering of groups is done based on which "\(" comes first
in the pattern (going left to right), NOT based on what is matched
first.
You can use
:%s/if(!\(.*\))/if(\1 == NULL)/gc
By putting .* in \( \) you make numbered captured group, which means that the regex will capture what is in .*
When the replace starts then by using \1 you will print the captured group.
A macro is easy in this case, just do the following:
qa .............. starts macro 'a'
f! .............. jumps to next '!'
x ............... erase that
e ............... jump to the end of word
a ............... starts append mode (insert)
== NULL ........ literal == NULL
<ESC> ........... stop insert mode
q ............... stops macro 'a'
:%norm #a ........ apply marco 'a' in the whole file
:g/^if(!/ norm #a apply macro 'a' in the lines starting with if...
Try the following:
%s/if(!\(.\{-}\))/if(\1 == NULL)/gc
The quantifier .\{-} matches a non-empty word, as few as possible (more strict than .*).
The paranthesis \( and \) are used to divide the searched expression into subexpressions, so that you can use those subgroups in the substitute string.
Finally, \1 allows the user to use the first matched subexpression, in our case it is whatever is caught inside the paranthesis.
I hope this is more clear, more information can be found here. And thanks for the comment that suggests improving the answer.
In vim we can substitute with an sub-replace-expression. When the substitute string starts with \= the remainder is interpreted as an expression.
e.g. with text:
bar
bar
and substitute command:
:%s/.*/\='foo \0'/
gives unexpected results:
foo \0
foo \0
instead of:
foo bar
foo bar
The question is: How to evaluate expression with matched pattern in substitute?
When you use a sub-replace-expression, the normal special replacements like & and \1 don't work anymore; everything is interpreted as a Vimscript expression. Fortunately, you can access the captured submatches with submatches(), so it becomes:
:%s/.*/\='foo ' . submatch(0)/
You need :%s/.*/foo \0/
With :%s/.*/\='foo \0'/ you evaluate 'foo \0' but that's a string and it evaluates to itself.
You don't need to evaluate any expression for that, use a regex group and proper escapes
:%s /\(.*\)/foo \1/
How do I do a VIM search/replace with the following conditions:
a) the line contains str1
b) the line also contain str2
c) the line do NOT contain str3
on such a line, I do want to replace xxx with yyy
This will replace the () string in every line of a file containing the string return and the string aLib at some point after that:
:%s/return.*aLib.*\zs()\ze/(aHandle)/
The % is the operating range of the command, which includes all lines in the file.
\zs denotes the start of the replaced string and \ze denotes its end.
If you have to replace more than one instance per line, put a g at the end of the command after the last /. If you wish to confirm each substitution, put the c flag at the end.
By assuming the () string is never present if aHandle is present, this command doesn't answer your question exactly, but based on the sample provided in the comments, this may match your needs.
regex doesn't handle and, not very well. there are ways to do it, but bit tricky. A very simple function could solve your problem:
function! Rep()
let l = getline('.')
if stridx(l, 'str1')>=0 && stridx(l,'str2') >=0 && stridx(l,'str3')<0
execute 's/xxx/yyy/g'
endif
endfunction
you can
either write it in your .vimrc file.
or save it in a foo.vim file and open it with vim type :so %
then open your target file, type :%call Rep() you will see for example:
str1 str2 str3 xxx
str3 str2 xxx
str2 xxx
*str1 str2 xxx
*xxx str2 xxx str2 xxx str1
would be changed into:
str1 str2 str3 xxx
str3 str2 xxx
str2 xxx
*str1 str2 yyy
*yyy str2 yyy str2 yyy str1
I think replacing str1,str2,xxx,yyy to your real values in that function isn't hard for you, is it?
EDIT
your real problem seems to be much easier than the problem you described in question. try this line:
:%s/\(\s*return\s*aLib\.[^(]\+(\)\s*\()\)/\1aHandle\2/
Note that it could be written shorter only for your example working, but I want it to be secure.
I think #Kent's answer (the function) is the "most correct" when doing complex searches/substitutions. It's easier to change afterward, and to understand it also after a while, it's also quicker to write than this. But I think it can be interesting if it's possible to do this with a "oneliner".
I welcome comments about this not working, I find it interesting myself if it's possible, not if it's the "best solution".
A "oneliner" for all situations described in the original question.
:v/str3/s/\v(.*str1&.*str2)#=.{-}\zsxxx/yyy/g
Explanation:
:v/str3/ all lines NOT containing "str3"
s/ substitute
\v "very magic" (to not have to escape regex expressions like {}), :h \v
(.*str1&.*str2)#= positive look-ahead, :h \#=
.*str1 any character 0 or more ("greedy") followed by "str1", the preceding .* is important for both & and #= to work
& pattern before and after & must be present, different than | that is using "or", both patterns must start at same place, thats why .* is used before str1/2, :h \&
#= the atom before (in the parentheses) should be present, but the pattern is not included in the match, the atom must however start at the beginning of the line for this to work (.* makes sure of that).
.{-} any character 0 or more ("not greedy"), {-} instead of * is important if more than one occurrence of xxx should be substituted (not enough with the g flag in this case)
\zs sets the start of the match (what to substitute).
xxx finally, the string to substitute
/yyy/ replace the match with yyy
g all occurences on the line
This gives the same result as using the example in #Kent's answer, it will handle any order of str1, str2, str3 and xxx.
I repeat that this is an alternative if for some reason a function is not an alternative. As I understand OP, e.g. str2 is always after str1 in his case, so this is more a general solution for situations like this (and perhaps more of academic interest).
I'd like to repeat a search and replace as below:
Example:
set_path 1 -start -from [get_obj { A_1[0] B_2[1] .... Z_n[100] }]
replace to
set_path 1 -start -from [get_obj {xyz/A_1[0] xyz/B_2[1] .... xyz/Z_n[100]
hit Esc, and type:
:%s/array/xyz\/array/g
:%s/ \(\u\)/ xyz\/\1/g
\1 means the content matched in the first brackets.
It means replace every space and a uppercase letter to xyz and the uppercase letter.
To make this work with variably named array names, you could do something like this:
s:\v([^[ {]+\[[0-9]+\]):xyz/\1:g
\v turns on "very magic" regular expressions, see :help /magic.
[^[ {]+ ensures the only strings not starting with a bracket, space or curly brace are matched.
\[[0-9]+\] ensures that it "looks" like an array reference.
Escape characters cause a lot of trouble in R, as evidenced by previous questions:
Change the values in a column
Can R paste() output "\"?
Replacing escaped double quotes by double quotes in R
How to gsub('%', '\%', ... in R?
Many of these previous questions could be simplified to special cases of "How can I get \ out of my way?"
Is there a simple way to do this?
For example, I can find no arguments to gsub that will remove all escapes from the following:
test <- c('\01', '\\001')
The difficulty here is that "\1", although it's printed with two glyphs, is actually, in R's view a single character. And in fact, it's the very same character as "\001" and "\01":
nchar("\1")
# [1] 1
nchar("\001")
# [1] 1
identical("\1", "\001")
# [1] TRUE
So, you can in general remove all backslashes with something like this:
(test <- c("\\hi\\", "\n", "\t", "\\1", "\1", "\01", "\001"))
# [1] "\\hi\\" "\n" "\t" "\\1" "\001" "\001" "\001"
eval(parse(text=gsub("\\", "", deparse(test), fixed=TRUE)))
# [1] "hi" "n" "t" "1" "001" "001" "001"
But, as you can see, "\1", "\01", and \001" will all be rendered as 001, (since to R they are all just different names for "\001").
EDIT: For more on the use of "\" in escape sequences, and on the great variety of characters that can be represented using them (including the disallowed nul string mentioned by Joshua Ulrich in a comment above), see this section of the R language definition.
I just faced the same issue - if you want any \x where x is a character then I am not sure how, I wish I knew, but to fix it for a specific escape sequence,. say \n then you can do
new = gsub("\n","",old,fixed=T)
in my case, I only had \n