Search/Replace in Vim - regex

I want to delete all occurrences of square brackets that conform to this regex: \[.*\].*{, but I only want to delete the brackets, not what follows - i.e., I want to delete the brackets and what's inside them, only when they are followed by an opening curly brace.
How do I do that with Vim's search/replace?

You can use \zs and \ze to set the beginning and the end of the match.
:%s/\zs\[.*\]\ze.*{//g should work.
You are telling Vim to replace what is between \zs and \ze by an empty string.
(Note that you need the +syntax option compiled in your Vim binary)
For more information, see :help /\zs or :help pattern
Edit : Actually \zs is not necessary in this case but I leave it for educational purpose. :)

If you surround the last bit of your regex in parenthesis you can re-use it in your replace:
:%s/\[.*\]\(.*{\)/\1/g
The \1 references the part of the regex in parenthesis.
I like to build my search string before I use it in the search and replace to make sure it is right before I change the document:
/\[.*\]\(.*{\)
This will highlight all the occurrances of what you will replace.
Then run the %s command without a search term to get it to re-use the last search term
:%s//\1/g

How about:
:%s#\[.*\]\ze.*{##g
Note that the \ze item marks the end of the match, so anything that follows is not replaced.

This will run your regex on the current file:
:%s/\[.*\]\(.*{\)/\1/g

Related

Append End of Line with Substring from Current Line [duplicate]

This question already has an answer here:
Replace with whole match value using Notepad++ regex search and replace
(1 answer)
Closed 9 months ago.
I've scoured Stack Overflow for something just like this and can't seem to come up with a solution. I've got some text that looks like this:
command.Parameters.Add("#Id
command.Parameters.Add("#IsDeleted
command.Parameters.Add("#MasterRecordId
command.Parameters.Add("#Name
...
And I would like the text to end up like this:
command.Parameters.Add("#Id", acct.Id);
command.Parameters.Add("#IsDeleted", acct.IsDeleted);
command.Parameters.Add("#MasterRecordId", acct.MasterRecordId);
command.Parameters.Add("#Name", acct.Name);
...
As you can see, I essentially want to append the end of the line with: ", acct.<word between # and second ">);
I'm trying this:
Find What: (?<=#).+?(?=\r) - This works, it finds the appropriate word.
Replace: \1", acct.\1); - This doesn't. It changes the line to (for Id):
command.Parameters.Add("#", acct.
Not sure what I'm doing wrong. I thought that \1 is supposed to be the "capture" from the "Find what" box, but it's not I guess?
The \1 backreference will only work if you have a capturing group in your pattern:
(?<=#)(.+?)(?=\r)
If you're not using a capturing group, you should use $& instead of \1 as a backreference for the entire match. Additionally, parentheses in the replacement string need to be escaped. So, the replacement string should be:
$&", acct.$&\);
You might also want to use $ instead of the Lookahead (?=\r) in case the last line isn't followed by an EOL character.
Having said all that, I personally prefer to be more explicit/strict when doing regex substitution to avoid messing up other lines (i.e., false positives). So I would go with something like this:
Find: (\bcommand\.Parameters\.Add\("#)(\w+)$
Replace: \1\2", acct.\2\);
Note that \w will only match word characters, which is likely the desired behavior here. Feel free to replace it with a character class if you think your identifiers might have other characters.
You could also omit the lookbehind, and match the # and then use \K to clear the current match buffer.
Then you can match the rest of the line using .+
Note that you don't have to make the quantifier non greedy .*? as you are matching the rest of the line.
In the replacement, use the full match using $0
See a regex demo for the matches:
Find what:
#\K.+
Replace with:
$0", acct.$0\)
If there must be a newline to the right, you might also write the pattern as one of:
#\K.+(?=\r)
#\K.+(?=\R)

How in notepad++ find/replace text between slashes?

How to find the text between the second and fourth slashes in a path like /folder/subfolder-1/subfolder-2/subfolder-3? I’m trying to replace this with something like /folder/new-folder/subfolder-3.
The most important for me is to be able to find the part after the n-th slash.
I tried the regex /((.*?)/){3}, but it doesn’t work.
Using Match resetter \K meta-character you are able to do it in a simpler way.
Find:
/.*?/\K(.*?/){2}
Replace with:
new-folder/
One way you could to it is by using this string in the pattern to replace
(/.+?)(/.+?){2}(/\S+)
And use this one in your pattern to replace it with
$1/new-folder$3
From your string:
/folder/subfolder-1/subfolder-2/subfolder-3
(/.+?) will match /folder as $1
(/.+?){2} will match /subfolder-1/subfolder-2 as $2 (not used)
(/\S+) will match everything that isn't a space, in this case/subfolder-3 as $3
Leaving you room to insert your new-folder in-between.
How can I just mark till the slash?
Find what: (/[^/]+/)[^/]+/[^/]+
Replace with: $1new-folder
To find text between second and forth slash you can use the regex ^(/[^/]*/)([^/]*/[^/]*) then you can reference to the text between slashes with \2 when replacing the text.
To keep the text before the slashes you can enter something like \1myNewTextBetweenSlashes2and4.
In notepad++ Find by this:
(/[^/]+)(?:/[^/]+/[^/]+/)(.*)
And Replace by this:
\1\/new-folder/\2
Make sure that: .matches newline is not checked
{2} indicates 2 levels after first level will be repalced by new-folder
Find:
(\/.*?\/)(.*?\/){2}(.*)
Replace:
$1new-folder/$3
Demo: https://regex101.com/r/XIA3IN/3

Need simple regex (regular expression) for dynamic expression

I need a regex to replace this text:
("{scriptid}_*0123_00000000_ABC-Description*");
With this text:
("{scriptid}_*0123_00000000_ABC-Description*"));
Or in other words: *I have to add a second closing brace.
Explanation:
("{scriptid}_*0123_00000000_ABC-Description*");
("{scriptid}_4-digits_8-alphanumeric_X-alphanumeric-description");
I tried some expressions but it doesn't really work.
Could some one please help me?
A generic regex that matches all the lines ending with ');' (match also if there are trailing spaces) can be this:
s/\);\s*$/\)\);/
Test online here.
UPDATE: generic regex that adds a closing parenthesis, matches only lines starting with lr_start_transaction:
s/^\s*(lr_start_transaction.*\))\s*;\s*$/\1\);/
Test online here.
Anyway, if we are not talking about generic regex you have to also specify the language you are coding with (cause each regex engine is thinly different).
Consider also to include some lines that does not have to match.
Based on your initial string, you can select it with this:
/(\("\{scriptid\}_[0-9]{4}_[a-z0-9]{8}_[-a-z0-9]+"\));$/i
The $ matches the end of the line, and the i flag is for case-insensitive.
You can then replace with $1); (To simplify the replacement, I left the ; out of the capture group in the match.
http://refiddle.com/refiddles/5625058d75622d65a01c0000

putting text before the nth occurence in each line in Vim

I have a situation like
something 'text' something 'moretext'
I forgot to add more spacing the first time I created this file and now on each line I should put some whitespace before the 2nd occurence of ' .
Now I can't build a regex for this.
I know that:
my command should begin with :%s because I want it to be executed on all lines
I should use the {2} operator to pick the 2nd occurence ?
If my regex will match something I can put stuff before the match with &
The main problem for me is how to build a regex to match the second ' using the {} notation, it's frustrating because I don't where it's supposed to be inserted or if I should use the magic or non-magic regex in vim.
The result I'm looking for
something 'text ' something 'moretext'
You can use
:%s:\v(^[^']*'[^']*)':\1 ':
[^'] means everything except '
\1 is a backreference to the first captured group (...)
Basically what your doing here is capturing everything up to the second quote, and replacing the line up to (and including) this quote with what you've captured, a space, and a quote.
{2} doesn't mean "the second match", it means "two matches" so it's completely useless for the task.
You could use a substitution like this one or the one in Robin's answer:
:%s/[^']*'[^']*\zs'/ '
Or you could use something like this:
:g/ '[^']*' /norm 2f'i<space>
Yet another way to do it:
:%s/\v%([^']*\zs\ze'){2}/ /
Note: I am using very magic, \v, to reduce amount of escaping.
This approach uses \zs and \ze to set the start and end of the match . The \zs and \ze get set multiple times because of the quantifier, {2} but each occurrence of the group will change the \zs and \ze positions.
For more help see:
:h /\zs
:h /\v
Of course there is always sed, but the trick is getting the quote escaped correctly.
:%!sed -e 's/'\''/ &/2'

deciphering vim regex

I'm playing with vim-ruby indent, and there are some pretty complex regexes there:
" Regex used for words that, at the start of a line, add a level of indent.
let s:ruby_indent_keywords = '^\s*\zs\<\%(module\|class\|def\|if\|for' .
\ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure' .
\ '\|rescue\):\#!\>' .
\ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\#!\>'
With the help of vim documentation I deciphered it to mean:
start-of-line <any number of spaces> <start matching> <beginning of a word> /atom
<one of provided keywords> <colon character> <nothing> <end of word> ...
I have some doubts:
Is it really matching ':'? Doesn't seem to work like that, but I don't see anything about colon being some special character in regexes.
why is there \zs (start of the match) and no \ze (end of the match)?
what does \%() do? Is it just some form of grouping?
:\#! says to match only if there is not a colon, if I read it correctly. I am not familiar with the ruby syntax that this is matching against so this may not be quite correct. See :help /\#! and the surrounding topics for more info on lookarounds.
You can have a \zs with no \ze, it just means that the end of the match is at the end of the regex. The opposite is also true.
\%(\) just creates a grouping just as \(\) would except that the group is not available as a backreference (like would be used in a :substitute command).
you can check about matching ':' or any other string by copying the regex and using it to perform a search with / on the code you are working. Using :set incsearch may help you to see what is being matched while you type the regex.
the \zs and \ze don't affect what is matched, but instead determine which part of matched text is used in functions as :s/substitute(). You can check that by performing searches with / and 'incsearch' option set - you can start a search for a string in the text, which will be highlighted, then adding \zsand \ze will change the highlight on the matched text. There is no need to "close" \zsand \ze, as one can discard only the start or the end of the match.
It is a form of grouping that is not saved in temporary variables for use with \1, \2 or submatch(), as stated in :h \%():
\%(\) A pattern enclosed by escaped parentheses.
Just like \(\), but without counting it as a sub-expression. This
allows using more groups and it's a little bit faster.