Ali
Ali

Reputation: 456

Vim escape characters in functions

how can I escape the regexp \([''"]\)\(.\{-}\)\1 and *test in the following function

:%s/.*/\=substitute(submatch(0),"\([''"]\)\(.\{-}\)\1","*test","g")/

the first regex matches anything between quotation in each line and replace it with what ever matches the second regexp at the same line

thanks, Best

Edit: example:

select "foo" as subject from table where [subject_test]=true
union
select "bar" as subject from table where [subject_test]=true

should become

select "foo" as subject from table where [subject_foo]=true
union
select "bar" as subject from table where [subject_bar]=true

Upvotes: 1

Views: 3929

Answers (4)

244an
244an

Reputation: 1589

Don't know if I understand your question correctly.

When using the function substitute() there are other rules for pattern than when using e.g. :s///.
See this: :h substitute()
Some parts from that:

...
But the matching with {pat} is always done like the 'magic' option is set and 'cpoptions' is empty (to make scripts portable). 'ignorecase' is still relevant. 'smartcase' is not used.
...
Note that some codes in {sub} have a special meaning |sub-replace-special|. For example, to replace something with "\n" (two characters), use "\\n" or '\n'.

It's not clearly how to use special regexp codes but they should be used with double backslash if you are using double quotes for the pattern string, "\\" means the character \, and is the same as '\'.
These should be equivalent when using the function substitute():
'\([a-z]\)'
"\\([a-z]\\)"
And my favorite, using \v ("very magic") so I don't have to backslash some regexp expressions:
"\\v([a-z])"

Your example should then be (I have NOT considered if your pattern is correct or not)

substitute(submatch(0), '\v([''"])(.{-})\1', "*test", "g")
Or:
substitute(submatch(0), "\\v(['\"])(.{-})\\1", "*test", "g")

The tricky part is that in the function substitute() you are using the pattern as a string, that is not the situation when normally using pattern in the command line in e.g. :s///.


EDIT (again due to comment by OP):
Can't say that I understand the use of your example, but I couldn't resist to try to fix it with an ex command like the one in your question (I'm trying to learn about VIM at the same time). Here is a command that works, and gives the result you want, but again, I don't understand what the use is.
But it seems that the question is really to learn how to escape regexp in a string.
If the "string" is always before what to substitute (and only substitutes one test for each ""):

:%s/\v"([^"]+)".*_\zstest/\1/g

Explanation

  • \zs = start match, \v = use "very magic"
  • "([^"]+)" "match" all characters except " (minimum 1) between " and "
    (the "real match" hasn't started yet, but the match in the parentheses will be as submatch number 1 anyway)
  • .* all characters up to next expression:
  • _\zstest "match" _test, but \zs makes the "real match" to start after that, so it's only test that will be substituted.
  • /\1/ replace with submatch number 1

changed This wasn't "safe", I added some longer match (from @Kent's answer), and also make sure only lines that have "<any characters>" are processed.
If the "string" can be before or after what to substitute

:g/\v"[^"]+"/y w | s/\v\[\w*_\zstest\ze\]/\=matchstr(@w, '\v"\zs[^"]+\ze"')/g

Explanation

  • \v = "very magic"
  • g/\v"[^"]+" use lines that have "<some text>"
  • /y w yank line to reg. w (instead of using getline())
  • | to have one more command
  • \zs = start match, \ze = end match (quicker than using look-ahead etc.)
  • \w same as using [0-9A-Za-z_]
  • \[\w*_\zstest\ze\] "match" [<almost any characters>_test], but the "real match" to substitute is test because of the \zs and \ze
  • matchstr(str, match) returns the match in str
  • matchstr(@w, '\v"\zs[^"]+\ze"') get the characters between " and " from the line (using reg w)
  • ... and use that to replace the matched test
  • /g do it for all occurrences of [<almost any characters>_test] in the line

Upvotes: 2

Tom
Tom

Reputation: 16188

To escape characters which are using in a substitute function I use escape()

Escape the characters in {chars} that occur in {string} with a backslash.

Example: 
     :echo escape('c:\program files\vim', ' \')  
Results in:  
    c:\\program\ files\\vim

For you example you can use escape('\([''"]\)\(.\{-}\)\1','\').
This will expand to: \\(['"]\\)\\(.\\{-}\\)\\1

Upvotes: 1

cptstubing06
cptstubing06

Reputation: 322

In VimL, single-quoted strings don't interpolate backslashes, and double-quoted strings do.

So, note the difference between :echo '\' and :echo "\\". In your example, you used double quotes, and since you're not turning off magic, you have a ton of escaping to do. See :help magic... Since I found out about \v, people tell me I'm much more pleasant to be around.

Upvotes: 0

Kent
Kent

Reputation: 195049

is this ok for you?

%s/\[.\{-}_\zstest\ze\]/\=split(getline('.'), '"')[1]/

this works too (with your example), and straightforward:

%s/\[subject_test\]/\="[subject_".split(getline("."),'"')[1]."]"/

Upvotes: 1

Related Questions