How do you replace inside a replace?
I know you can get the current word under the cursor into the replace, but I want to perform a replace on it before having it as the output.
For example:
Having a document that has passed through the clbuttic filter and replacing words that you know have been affected for the worse, such as deinstitutionalization (Hint: Consbreastution of the United States of America). The file also has some words that are properly replaced.
Changing o to 0 in Wooloomooloo (and only for that word) throughout a document
A real world example (from my vim history) is being in a Latex document and running
%s/\\begin{table}\[h\]/\\begin{table}\[H\]/c
where I am duplicating the string just to get a minor change.
Replacing o to 0 is straightforward:
:s/o/0/g
Perhaps you want to know how to apply it to a (visual) selection?
:s/\%Vo/0/g
Edit Likely what you want (see comments)
:%s/\<\zs[Wolm]\+\>\ze/\=substitute(submatch(0), 'o', '0', 'g')/g
What this does:
[Wolm]\+ matches sequences consisting of just W,o,l,m
\<[Wolm]\+\> matches (independent) words of the same (so, Wooloomooloo, or mooW, Wlomo would all match, but not amool etc).
\zs marks the begin of the match for replace, \ze the end
\=substitute(submatch(0), 'o', '0', 'g') replaces the match (between \zs and \ze) but subsituting 0 for o
You can start from this pattern
replacing [Wolm]\+ with your actual target
adding optional context outside \zs...\ze so you can reduce matches
adding \c in the front of the pattern to enable case-insensitive matching
Try typing Ctrl-f while you're writing your :sub command. This will open the command-line window and allow you to use vim's normal mode to edit your command. If you press Enter in this mode, the current line will be executed. If you press Ctrl-c, you'll drop back to the command-line mode with the current line as the current text.
The command-line window is also what happens when you accidentally type q:. (I know I did that a lot before understanding what it's for. It also has history of your previous commands. Also try the same during a / search or type q/.
See also :help cmdline-window
Related
I'm trying to convert multiple instances of Unicode codes to their corresponding characters.
I have some text with this format:
U+00A9
And I want to generate the following next to it:
©
I have tried to select the code in visual mode and use the selection range '<,'> in command mode as input for i_CTRL_V but I don't know how to use special keys on a command.
I haven't found anything useful in the manual with :help command-mode . I could solve this problem using other tools but I want to improve my vim knowledge. Any hint is appreciated.
Edit:
As #m_mlvx has pointed out my goal is to visually select, then run some command that looks up the Unicode and does the substitution. Manually input a substitution like :s/U+00A9/U+00A9 ©/g is not what I'm interested in as it would require manually typing each of the special characters on every substitution.
Any hint is appreciated.
Here are a whole lot of them…
:help i_ctrl-v is about insert mode and ranges matter in command-line mode so :help command-mode is totally irrelevant.
When they work on text, Ex commands only work on lines, not arbitrary text. This makes ranges like '<,'> irrelevant in this case.
After carefully reading :help i_ctrl-v_digit, linked from :help i_ctrl-v, we can conclude that it is supposed to be used:
with a lowercase u,
without the +,
without worrying about the case of the value.
So both of these should be correct:
<C-v>u00a9
<C-v>u00A9
But your input is U+00A9 so, even if you somehow manage to "capture" that U+00A9, you won't be able to use it as-is: it must be sanitized first. I would go with a substitution but, depending on how you want to use that value in the end, there are probably dozens of methods:
substitute('U+00A9', '\(\a\)+\(.*\)', '\L\1\2', '')
Explanation:
\(\a\) captures an alphabetic character.
+ matches a literal +.
\(.*\) captures the rest.
\L lowercases everything that comes after it.
\1\2 reuses the two capture groups above.
From there, we can imagine a substitution-based method. Assuming "And I want to generate the following next to it" means that you want to obtain:
U+00A9©
you could do:
v<motion>
y
:call feedkeys("'>a\<C-v>" . substitute(#", '\(\a\)+\(.*\)', '\L\1\2', '') . "\<Esc>")<CR>
Explanation:
v<motion> visually selects the text covered by <motion>.
y yanks it to the "unnamed register" #".
:help feedkeys() is used as low-level way to send a complex series of characters to Vim's input queue. It allows us to build the macro programatically before executing it.
'> moves the cursor to the end of the visual selection.
a starts insert mode after the cursor.
<C-v> + the output of the substitution inserts the appropriate character.
That snippet begs for being turned into a mapping, though.
In case you would like to just convert unicodes to corresponding characters, you could use such nr2char function:
:%s/U+\(\x\{4\}\)/\=nr2char('0x'.submatch(1))/g
Brief explanation
U+\(\x\{4\}\) - search for a specific pattern (U+ and four hexadecimal characters which are stored in group 1)
\= - substitute with result of expression
'0x'.submatch(1) - append 0x to our group (U+00A9 -> 0x00A9)
In case you would like to have unicode character next to text you need to modify slightly right side (use submatch(0) to get full match and . to append)
In case someone wonders how to compose the substitution command:
'<,'>s/\<[uU]+\(\x\+\)\>/\=submatch(0)..' '..nr2char(str2nr(submatch(1), 16), 1)/g
The regex is:
word start
Letter "U" or "u"
Literal "plus"
One or more hex digits (put into "capture group")
word end
Then substituted by (:h sub-replace-expression) concatenation of:
the whole matched string
single space
character by UTF-8 hex code taken from "capture group"
This is to be executed in Visual/command mode and works over selected line range.
When I type /foo and then enter, is there a way to mark occurrence for all highlighted words? Right now, the /search seems pretty useless compared to the regular atom search, since it only highlights but doesn't let you replace.
The key / is used for searching, whereas :s for substitutions (i.e. replacements). So to replace foo with bar you can do:
:%s/foo/bar/gc
Here % means look for replacements in the entire file, and the last gc are replacement flags. The Vim documentation provides a great explanation of the topic and it can be accessed by typing :help subs. To learn more about replacement flags: :h flags.
Some more suggestions for a good workflow (at least in Vim itself):
After using /foo to locate a match, and you only want to replace that one: As the cursor is at the start of the match, you can use ce, cE or more generally cgn (gn selects the current / next match; it's a recent addition in version 8.0).
If you want to replace all matches, you don't need to repeat the search pattern in the :substitute command; an empty {pattern} there will recall the search pattern. So, you can briefly write :%s//bar/g (+ c to interactively influence replacements).
It seems I can't mark occurrence if I press enter. However, I can do some things if I haven't pressed enter.
cmd-o marks all search occurrences
ctr-cmd-c waits for you to specify a range, and then changes all search occurrences
How I can select all the text start with foo_list starting from line 4 (see. below code) and rename them with list_values or any other preferred name ? Please note, I don't want to change in the first line.
Thanks in advance !
foo_list = [5, 2, 3, 1, 4]
def reverse_list_1():
foo_list=[0,10,20,40]
for i in reversed(foo_list):
print i,
foo_list=[0,10,20,40]
print foo_list[::-1]
for i in reversed(foo_list):
print i,
length = len(foo_list)
for i in range(length):
print foo_list[length-i-1],
Preferable solution: key map in the .vimrc or .gvimrc file, don't want to use any plugin.
That's a job for :substitute. You can specify the range with explicit line numbers (here: 4 to end of buffer $, or maybe next empty line /^$/):
:4,$substitute/\<foo_list\>/list_values/g
You can also first move to the first line and use the .,$ range.
Since that's still a lot of typing, you can pull in the current word (assuming you first position the cursor on the foo_list occurrence in line 4) into the command line via <C-R><C-W>.
Or, for a plugin solution, my ChangeGlobally plugin provides a mapping that avoids the use of :s.
:%s/foo_list/list_values/gc
This command says to replace the word foo_list with list_values in the whole document, asking for confirmation each time. Then for the first occurrence of foo_list on line 1, press n (to indicate NO) , and press y (to indicate YES) for all further occurrences to replace them. This solution works when you have to replace a few words. You can read the command as follows:
In the whole document (%), substitute (s) the word foo_list with list_values and do this globally (g), asking for confirmation (c) each time. For more options in the substitute command type :help :s in vim.
Solution 2 :
When there are thousands of words to replace, you surely don't want to type a y/n confirmation each time (which is enabled by the c flag in the end in the above command).
Take your cursor to line 4 and run
:.,$s/foo_list/list_values/g
Read the above command as from here (.) to the end of file (,$)
replace (s) the word foo_list with list_values
globally (g).
For small changes like this I like to use the gn motion. The gn motion visually selects the current search pattern. This makes for a powerful search/replace method when combining the gn motion with the change, c, operator and the repeat command, ..
Basic steps:
Make foo_list your search pattern. e.g. /foo_list or via *
Use c and gn to change the first foo_list. e.g. cgnbar_list<esc>
Now repeat that change on the next search result via .
Use n to advance to the next search results. (Hit n twice to skip an occurrence)
Keep using n and . until done
There is a nice Vimcasts episode on this topic: Operating on search matches using gn
For more information see:
:h gn
:substitute is the 'correct' way, but if you're only making a few changes, and you are not very experienced with ex commands, sometimes it takes longer to think through the command than to bounce through the list of changes you want to make using motions.
If you start with your cursor on the first instance of foo_list, hit '*' to jump to the next occurrence in the file. Hit 'ce' to delete to the end of the word and enter insert mode. Type in your new variable name and return to normal mode. Now you can jump through the rest of the file using 'n' to jump to the next occurrence (or 'N' to go back), and '.' to repeat your last edit action.
In VIM, it's really easy to change a word of text to use uppercase or lowercase:
# in visual mode
# change word to uppercase
gUw
# change word to lowercase
guw
Is there a simple way to modify the word to use initial caps?
Assuming cursor is at the beginning of the word, use
gUl
(if the word was all-lowercase) or
gUllgue
to explicitly make the first letter capital and other lower case.
It's the same that you used, only instead of w (word motion) you use l (one symbol motion).
If the cursor is somewhere in the middle of the word, prepend b (go to the beginning of the word) to the commands above.
You can map some key to do this if you use it often.
I'd suggest moving to the beginning of the word with whatever motion command(s) you want, then pressing ~. This behavior is affected by the tildeop option, see :help ~ and :help tildeop for more info.
Depending on what your use-case is, any of the following may work.
Use ~ to toggle the case of the letter under your cursor.
Use :s/\<\(\w\)\(\w*\)\>/\u\1\L\2/ to search for a word, upper-case the first letter, and lower-case the rest.
guiwgUl to lower-case the word your cursor is on and then upper-case the first letter.
If you're on the word:
bgUl
If you're at the beginning of the word:
gUl
Unpacking that: b goes back one word (or to the beginning of the word you're on), gU upcases over movement, l moves right one character (which will be the first letter in the word).
Side note:
I have a plugin (well, it's not its main purpose though) that is able to convert names between camel case, underscore separated words, etc. Move the cursor on an identifier, and type :NameConvert lower_camel_case for instance (the command supports completion (<tab>, <c-d>) to display all the possible naming schemes)
To install it, you'll need lh-dev, and lh-vim-lib.
There is a function toupper which you can use to make conversion. Even in substitution you can use that. Like find all sentence beginnings, and convert the first character to upper case, as explained here: search and replace
In Unix the ^ allows you to repeat a command with some text substituted for new text. For example:
csh% grep "stuff" file1 >> Results
grep "stuff" file1
csh% ^file1^file2^
grep "stuff" file2
csh%
Is there a Vim equivalent? There are a lot of times I find myself editing minor things on the command line over and over again.
Specifically for subsitutions: use & to repeat your last substitution on the current line from normal mode.
To repeat for all lines, type :%&
q: to enter the command-line window (:help cmdwin).
You can edit and reuse previously entered ex-style commands in this window.
Once you hit :, you can type a couple characters and up-arrow, and it will character-match what you typed. e.g. type :set and it will climb back through your "sets". This also works for search - just type / and up-arrow. And /abc up-arrow will feed you matching search strings counterchronologically.
There are 2 ways.
You simply hit the . key to perform an exact replay of the very last command (other than movement). For example, I type cw then hello to change a word to "hello". After moving my cursor to a different word, I hit . to do it again.
For more advanced commands like a replace, after you have performed the substition, simply hit the : key then the ↑ up arrow key, and it fills your command line with the same command.
To repeat the previous substition on all lines with all of the same flags you can use the mapping g&.
If you have made a substitution in either normal mode :s/A/B/g (the current line) or visual mode :'<,>'s/A/B/g (lines included in the current selection) and you want to repeat that last substitution, you can:
Move to another line (normal mode) and simply press &, or if you like, :-&-<CR> (looks like :&), to affect the current line without highlighting, or
Highlight a range (visual mode) and press :-&-<CR> (looks like :'<,'>&) to affect the range of lines in the selection.
With my limited knowledge of Vim, this solves several problems. For one, the last visual substitution :'<,'>s/A/B/g is available as the last command (:-<UP>) from both normal and visual mode, but always produces an error from normal mode. (It still refers to the last selection from visual mode - not to the empty selection at the cursor like I assumed - and my example substitution exhausts every match in one pass.) Meanwhile, the last normal mode substitution starts with :s, not :'<,'>s, so you would need to modify it to use in visual mode. Finally, & is available directly from normal mode and so it accepts repetitions and other alternatives to selections, like 2& for the next two lines, and as user ruohola said, g& for the entire file.
In both versions, pressing : then & works as if you had pressed : and then retyped s/A/B/, so the mode you were in last time is irrelevant and only the current cursor line or selection determines the line(s) to be affected. (Note that the trailing flags like g are cleared too, but come next in this syntax too, as in :&g/: '<,'>&g. This is a mixed blessing in my opinion, as you can/must re-specify flags here, and standalone & doesn't seem to take flags at all. I must be missing something.)
I welcome suggestions and corrections. Most of this comes from experimentation just now so I'm sure there's a lot more to it, but hopefully it helps anyway.
Take a look at this: http://vim.wikia.com/wiki/Using_command-line_history for explanation.