Search and replace with parameters - search

I have a long YAML config file which I'd like to change.
I would like to replace an attribute "url" with as dictionaries of url, for instance change,
url: https://bla.bla
into
url: {my_key: https://bla.bla}
So basically, for a given string "s" which is found after url key, I'd like to wrap it around {key: s}
Is there an efficient way to do this using basic text editor find and replace features? I am using spacemacs by the way

You can run: Meta+x query-replace-regexp, which for me is mapped to CTRL+Meta+% in "regular" emacs.
When prompted for a regexp you can try:
.*url:[ ]*\(.*\)
or the slightly more rigorous option that will remove leading and trailing spaces:
^.*url:[ ]*\([^ ]+\)[ ]*$
and hit RETURN.
When prompted for replacement text, try:
{ my_key: \1 }
If the pattern matches, you just hit y to confirm, or ! to auto-confirm the rest. Backup your data first. In the regular expression, the pattern between parentheses gets "captured" (there can be multiple captures). In the replacement, the \1 is replaced with the first captured pattern. Invest some time in learning regular expressions. They are very powerful.

Related

Multi-line edit starting at the same character (= sign) [no macros?]

I'm working on an ansible playbook, where VIm seems to prove to be an extremely useful tool for (lots of similar patterns in style/formatting and such), and I'm hoping to take my current situation (since been written) to turn it into a Vim lesson.
I've made extensive use of code blocks to make multi-line edits, but I think I've reached their limit and wanted to reach out to figure out how I might approach making line edits more dynamically. In this scenario, I have a block of code that I'm trying to transform
from:
rcon.port=25575
rcon.password=strong-password
enable-rcon=true
into:
- { regexp: '^rcon.port', line: 'rcon.port=25575' }
- { regexp: '^rcon.password', line: 'rcon.password=strong-password' }
- { regexp: '^enable-rcon', line: 'enable-rcon=true' }
To do that, the first part is fairly simple. Shift-I, then ctrl-V for block, traverse lines to edit, type - { regexp: '^" to get to the following:
- { regexp: '^rcon.port=25575
- { regexp: '^rcon.password=strong-password
- { regexp: '^enable-rcon=true
Unfortunately, from there I'm a bit lost as the macros (and whether or not that's overkill or not) are still a bit unclear to me. Are there any possible approaches to solve this problem other than macros?
I'm not looking for a full solution, but simply a hint for the best (or only approach) here, and if there are any tricks to thinking about this in the Vim way.
Any links to good documentation/learning resources for macros would be AWESOME as well! I'm still new to Vim, so bear with me... thanks!
Building off #Stephen Warren's answer the following works as required:
:%s/^\(\(.\+\)=.\+\)/- regex: '\2', line: '\1' }/
The match section is:
From the beginning of the line ^
It has two groups rather than one \(\)
The first group is the outer one that matches the entire line
The second group is the inner group that matches up to the =
Match one or more characters \+ is used rather than the greedy * for matching either side of the =
The replace section:
Basically your expected output calling on the previously matched groups \1 and \2
Perhaps something like the following regular expression substitutions:
:%s/^\(.*\)$/- { regexp: '^\1' }/
Or with all relevant lines visually selected:
CTRL-o
:s/^\(.*\)$/- { regexp: '^\1' }/
I guess I should explain that a bit more:
: Enter command mode.
% Apply to all lines.
s Substitute.
/xxx/yyy/ Replace xxx with yyy.
^ Anchor at start of input string
(xxx) (in match string) capture whatever matches xxx.
\1 (in replacement string) replace with whatever matched (xxx).
.* Match any amount of any characters.
$ Anchor at end of input string.
Replacement string is emitted into the result literally without any interpretation, except for stuff like \1.

Appending to the end of a pattern with a word in the middle using vim

I have a file that is out-of-date and needs to be updated. The names have changed somewhat and I would like to clean them all up using a single substitution.
Here's what I'm trying to accomplish:
foo.foo_[single word] -> foo_bar.foo_[single word]_bar
where a single word is a string of n characters. In the file, they are always preceded by an underscore, but it needs to have "_bar" appended. There is always a "." after these instances, so I thought the following might work:
%s/foo\.foo_*\./foo_bar\.foo_*_bar\./g
Sadly, the first part doesn't even match what I want, so I'm back to square one.
I would first change:
foo_[word] -> foo_[word]_bar
and then
foo. -> foo_bar.
i.e.:
%s,\(foo_\w\+\),\1_bar,g|%s,foo\.,foo_bar\.,g
There are many ways to skin a cat but following should do the trick
%s/\vfoo.foo_(\w+)/foo_bar.foo_\1_bar/gc
what loosely translates to
\v Very Magic (:help magic)
foo.foo_ Search for exact string
(\w+) Search for a "word" and store in a backreference
/foo_bar.foo Replace search pattern with this exact string
\1 appended with backreference 1
_bar appended with _bar
or if you don't want to repeat the search in the replace part, you can go a bit nuts with backreferences and use
%s/\v(foo)\.foo_(\w+)/\1_bar.\1_\2_bar/gc
The most important parts you were missing were
using backreferences (:helpgrep backref)
using character classes (:h \w)
using repetition (_* is searching for 0 or more underscores. You probably meant _.*)

Delete text with GREP in Textwrangler

I have the following source code from the Wikipedia page of a list of Games. I need to grab the name of the game from the source, which is located within the title attribute, as follows:
<td><i>007: Quantum of Solace</i><sup id="cite_ref-4" class="reference"><span>[</span>4<span>]</span></sup></td>
As you can see above, in the title attribute there's a string. I need to use GREP to search through every single line for when that occurs, and remove everything excluding:
title="Game name"
I have the following (in TextWrangler) which returns every single occurrence:
title="(.*)"
How can I now set it to remove everything surrounding that, but to ensure it keeps either the string alone, or title="string".
I use a multi-step method to process these kind of files.
First you want to have only one HTML tag per line, GREP works on each line so you want to minimise the need for complicated patterns. I usually replace all: > with >\n
Then you want to develop a pattern for each occurrence of the item you want. In this case 'title=".?"'. Put that in between parentheses (). Then you want add some filling to that statement to find and replace all occurrences of this pattern: .?(title=".?").
Replace everything that matches .?(title=".?").* with \1
Finally, make smart use of the Textwrangler function process lines containing, to filter any remaining rubbish.
Notes
the \1 refers to the first occurrence of a match between () you can also reorder stuff using multiple parentheses and use something like (.?), (.) with \2, \1 to shuffle columns.
Learn how to do lazy regular expressions. The use of ? in these patterns is very powerfull. Basically ? will have the pattern looking for the next occurrence of the next part of the pattern not the latest part that the next part of your pattern occurs.
I've figured this problem out, it was quite simple. Instead of retrieving the content in the title attribute, I'd retrieve the page name.
To ensure I only struck the correct line where the content was, I'd use the following string for searching the code.
(.)/wiki/(.)"
Returning \2
After that, I simply remove any cases where there is HTML code:
<(.*)
Returning ''
Finally, I'll remove the remaining content after the page name:
"(.*)
Returning ''
A bit of cleaning up the spacing and I have a list for all game names.

How to share searchText between vim search and vim substitute?

When i need to replace a string with a new string in vim.
First i would use search-mode to check that the search pattern is correct.
/search pattern
Then use the 's' command to do substitution.
:%s/search pattern/new string/
The search pattern need to type twice. If it is too complex, it would be boring.
Is there a method to avoid this?
You can simply omit the pattern in the substitution command, e.g.
:%s//new string/
This is documented in :help last-pattern (emphasis mine):
The last used pattern and offset are remembered. They can be used to
repeat the search, possibly in another direction or with another
count. Note that two patterns are remembered: One for 'normal' search
commands and one for the substitute command ":s". Each time an empty
pattern is given, the previously used pattern is used.
Also (in addition to Marco Baldelli's correct answer), the last search pattern is stored in the special register /. You can insert this in the command-line via Ctrl + R, followed by /. (This also works in insert mode, and also with other registers.) It's helpful when you want to tweak your search pattern before substituting.

replacing part of regex matches

I have several functions that start with get_ in my code:
get_num(...) , get_str(...)
I want to change them to get_*_struct(...).
Can I somehow match the get_* regex and then replace according to the pattern so that:
get_num(...) becomes get_num_struct(...),
get_str(...) becomes get_str_struct(...)
Can you also explain some logic behind it, because the theoretical regex aren't like the ones used in UNIX (or vi, are they different?) and I'm always struggling to figure them out.
This has to be done in the vi editor as this is main work tool.
Thanks!
To transform get_num(...) to get_num_struct(...), you need to capture the correct text in the input. And, you can't put the parentheses in the regular expression because you may need to match pointers to functions too, as in &get_distance, and uses in comments. However, and this depends partially on the fact that you are using vim and partially on how you need to keep the entire input together, I have checked that this works:
%s/get_\w\+/&_struct/g
On every line, find every expression starting with get_ and continuing with at least one letter, number, or underscore, and replace it with the entire matched string followed by _struct.
Darn it; I shouldn't answer these things on spec. Note that other regex engines might use \& instead of &. This depends on having magic set, which is default in vim.
For an alternate way to do it:
%s/get_\(\w*\)(/get_\1_struct(/g
What this does:
\w matches to any "word character"; \w* matches 0 or more word characters.
\(...\) tells vim to remember whatever matches .... So, \(w*\) means "match any number of word characters, and remember what you matched. You can then access it in the replacement with \1 (or \2 for the second, etc.)
So, the overall pattern get_\(\w*\)( looks for get_, followed by any number of word chars, followed by (.
The replacement then just does exactly what you want.
(Sorry if that was too verbose - not sure how comfortable you are with vim regex.)

Resources