If I had a sentence - "I know a person named Ted who likes //^$" - or basically a sentence with a lot characters I didn't feel like escaping, and I wanted to insert copies of that sentence with different names (e.g. John Mary Bob)...
Can a for loop do this by copying the sentence, pasting it as the next line, and then subbing out the name? How do I tell it where to paste?
I could also paste the list of names in first and then sub the sentence in around the names - eg :s/^/I know a person named /, but I find that if there is a lot of text with a lot characters to escape, I'll probably make an error somewhere and waste time having to scrutinize the expression.
So then, is there an easier way to grab the contents from the sentence and put it into a substitute command?
You can do this with a macro in vim.
Check here for a explanation of vim macros: http://vim.wikia.com/wiki/Macros.
It's a lot easier than using regex stuff.
Like Chiel92 suggests, a macro is the easiest way. Suppose you have a text file that looks like this:
I know a person named XXX who like //^$
John
Mary
Bob
Personally I would:
Go to line 1, and copy the line into a named buffer: :1<enter>"iyy
Go to line 3 and record a macro that copies the name on the line, pastes the contents of the i buffer, and then replaces XXX with the name that was on the line:
Go to line 3: :3<enter>
Start recording a macro to register m: qm
Delete the name into a different register: "od$
Paste in the template: "ipkdd
Replace XXX with the name: :s/XXX/^Ro/
Go to the next line: j
Finish recording: q
For each name line you can now replay the macro: #m or ##
Note: when making macros and have problems replaying I always find it helpful to look at the contents of my recording registry. You can just do ^R^Rm to see all the commands you recorded.
Related
I have a file with a few hundred lines of code. I'd like to search through the file and change all of a variable name to uppercase. Imagine like this:
:%s/variable_name/<gUaw>/g
...would change variable_name to VARIABLE_NAME
Is there a more 'vim' way to do this than just running the search/replace for each variable, typing both the original name and the uppercase name?
#phd got it: :%s/variable_name/\U&/g. Thanks for the assist!
You can create a macro for that:
First, search for your pattern:
/yourPattern
Then count the number of occurrences:
:%s///n
Finally, create your macro:
qqngUawq
qq starts recording the macro in the register q, n goes no the next occurenceand the finalq` stops the recording.
Execute it n-1th times (the nth time was done by creating the macro):
42#q
Here n-1 == 42 ;-) replace 42 by your number of occurences.
I have a list of products to place on a rails seed and I would like to instead of put brackets one by one on the list with a command place the brackets on the whole list?
for example:
1. Dakine
2. Dale of Norway
3. Dan Post
1. ["Dakine"],
2. ["Dale of Norway"],
3. ["Dan Post"],
I searched on the help but did not find any about. Thanks.
You can record a macro in Vim and repeat that.
If you are on number 1, you can do following:
qqf a["Esc$a"],Esc0jq
Explanation:
qq: Start recording macro in register q
f: Go to first space character
a: : Insert after (the space character from above)
\[": Insert those characters
Esc: Back to normal mode
$: Go to end of line
a: Insert after (end of line)
"],: Insert the characters
Esc: Back to normal mode
0: Jump to start of line
j: Go down one line
If you have 100 such lines, you can do 100#q to achieve your result.
With vim substitute command:
:%s/.*/["&"]/
If you don't want to operate on all lines, then select the ones you want to transform or note the related line numbers, and then type :s/..... without the %. You'll see actually :'<,'>s this range represent the visually selected lines, and vim adds it automatically in visual mode.
On Atom you can enable the find to use Regex in the search(there is a button next to the search field)
Then you can search for something like (^.*$) to get every line separated by groups and in the Replace field you use ["$1"],. The $1 represents the value matched by the Regex.
Then just do a Replace All and remove the last comma in your list if needed.
I am trying to delete a range of lines into a register a. Is this the easiest way to achieve this?
:5,10d a
The definition of "easiest" depends on what do you have, and what do you want to do
if you have a start line number and end number, e.g.
:2349,5344d a
is the easiest way.
You don't have to consider the questions like
"where is my cursor?"
"how many lines would be removed?"
...
If you are about to remove a small amount of lines, particularly they are on same screen. (You could use relative-linenumber.) for example: "a5dd but you have to move your cursor to the first line you want to delete. And this could be done by option 1 too: 5:d a<CR> (vim will automatically translate it into .,.+5d a<CR>)
If you just know the 1st line of deletion, and find the last line you want to delete by reading your text, (of course, small amount of lines) you could press V, and press j by reading, when it reaches the deletion ending border, press "ad
If the "range" in your question is the "range" concept in vim, The first option would be better. since it could be 234,540, it could be 1;/foo, /foo/,/bar/... :h range see detail
so back to the first sentence in my answer, There is no absolutely easiest way. It all depends on what do you have, and what do you want to do.
The other way to achieve this would be to highlight the range of lines in visual line mode. (Shift-V)
Then type "ad while in visual line mode. This will put the deleted lines into the a register.
" followed by a register puts the next delete, yank or put into that register.
Below is the documentation for " (quote)
*quote*
"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank
or put (use uppercase character to append with
delete and yank) ({.%#:} only work with put).
Another example of deleting multiple lines and putting it in a register. To delete 6 lines and put them in a register you can got to the line and type "a6dd. This puts the 6 deleted lines into register a.
:/From book:/,/$/ cmd_copy chapters_from_match_#From_book#_until_end_of_line.txt
I tried not to use words "write", "put" or "read" as VIM has special meaning for them. I try to copy (sorry not referring to VIM's copy-command) the thing between matches to a file. How do you do it, without copying the whole lines?
Dummy example
TEXT:
do not copy me dummy1 hello world
please copy me dummy2 do not copy me
some enters, should work also with enters btw the matchpoints dummy1 not yet!
not yet!
copy will end soon! dummy2
COPIED:
hello world please copy me
or
dummy1 hello world please copy me dummy2
To copy text between start and end, use the following sequence of Normal
mode commands.
/start/e+1Entery/end/Enter
The first command searches for the next occurrence of the pattern matching
start of a text fragment to copy, and positions the cursor to the first
character after the match. The second one yanks everything until the next
match of the ending pattern.
Depending on the context in which the commands will be used, they could be
rewritten as an Ex command, a mapping or a macro.
Ex command
:norm!/start/e+1^My/end/
(Type ^M as Ctrl+V, Enter.)
Mapping
:nnoremap <leader>y /start/e+1<cr>y/end/<cr>
Macro
:let #y = "/start/e+1\ry/end/\r"
(Or record a macro the usual way: type q, register to store the
macro, say, y, then commands as it shown at the top of the answer
followed by final q.)
so, why not use
:1s/^\_.\{-}dummy1// "first line: delete everything until first occurrence of dummy1
:%s/dummy2\zs\_.\{-}\zedummy1/\n/
:1s/\_.*dummy2\zs\_.*// "delete from last occurrence of dummy2 till EOF
I have a bunch of lines that I'd like to split into two columns, and get the data from each column. The data looks something like this:
current_well.well_number
current_well.well_name
current_well.well_type_code
well_location.section
well_location.range
Essentially what I'd like to do is split the line based off of the period, turn the data into two columns, and then grab the data for each column. I know this can be done in Excel, but I'm really interested in VIs solution for this problem. I know that
%s/\./
will format the string with empty spaces. But once I have the data looking like:
current_well well_number
current_well well_name
current_well well_type_code
well_location section
well_location range
How do I grab all the values for each column so I can paste it into another application?
The linux column command works well for creating the columns
:%!column -s . -t
Then use block copy.
One option is to use this Align plugin to line up the periods so you can more easily select a column in Visual Block mode. e.g. if you do this:
:%Align \.
You'll end up with:
current_well . well_number
current_well . well_name
current_well . well_type_code
well_location . section
well_location . range
If you don't want to use a plugin, try padding your columns with spaces. e.g. for your text:
:%s/\v(.*)\.(.*)/\=printf("%-16s %s", submatch(1), submatch(2))/
That'll leave you with:
current_well well_number
current_well well_name
current_well well_type_code
well_location section
well_location range
Then you can Ctrl-V and select a column of text to copy. Just make sure you pick a column width wider than your widest value.
I've run into this problem a number of times. Changing the dots to tabs will line them up mostly nice, but not really. It's true that all the columns will start on a tabstop, but there's no guarantee that they'll be on the same tabstop. For instance, if this was your original text:
lt1tab.value1
gt1tabstop.value2
and you do:
%s/\./\t/g
and assuming a tabstop is 8 spaces, you'll get:
lt1tab value1
gt1tabstop value2
What you might want to do instead is remove everything but the last column (or whichever column you want). For instance:
%s/^.*\.//
will leave you with:
value1
value2
Which you can easily copy and paste.
If you don't have to use Vim, you can use unix's cut to do what you want:
cut -f2 -d. input_file > output_file
I do this all the time, simply by padding with a lot of space:
%s/./ /
Then <c-v> to enter block mode in the empty space, draw the column position I want, < to shift the text to the right toward my column, then hold down .. Takes seconds.
Another way you can do it if you know the specific column position you want to line up on: go to the first line and start recording (qq), find your delimeter (f.), insert a bunch of space (20i <esc>), delete space back to a specific column (d15|), then move down a line (j). Then you just hold down shift and roll your fingers across #Q a bunch of times (or use a count 10#q) until all the columns are lined up. :)
Obviously, the above methods with block select and/or Excel are easier. But I'm a masochist and I decided to assume you didn't have access to either of those and try to do it with only vi commands. Here's the horrible thing I thought up:
My basic plan is to turn the list of joined columns into two lists, one after the other. This basically involves breaking each row into two lines, then copying every other line to the end of the file.
So, first we have to break each line into two lines with this command:
:%s/\./^M/
Next, swing by the bottom of the file and create an empty line, then return to the first line. This will help with readability later.
Go[Esc]
:1
Now, you need to map the following sequence to your favorite key:
:map [Key] mkjddGp'kj
(For the record, this marks the current row, deletes the row below it, pastes that row at the bottom of the file, returns to the row you started from, and then moves to the next row.)
Finally, press the mapped key once for every row in your list. So, with the example list, you'd press it 5 times. Make sure you start from the first line in the list!!
What you'll have at the end is the following:
current_well
current_well
current_well
well_location
well_location
well_number
well_name
well_type_code
section
range
You can now easily copy each list to wherever you need to put them.
Ctrl V selects a column
Why not block visual mode ? C-v, select what you want, and paste it in some other application.
For that kind of pasting, you should probably set
:set guioptions+=a
as well.
Hmm, now that I've re-read your question. Are you asking how to divide the data into columns, or how to paste it in some other app ?
I think I got it now (3rd reading).
Do as you've done and get the spaces where the dots used to be. Then do another substitution, and replace the spaces with tabs, each tab being, 15 or something. It will line them up nicely.
Then you can select and copy them to wherever.
You can also match the regex to select the second column for example, but although it is light up like a christmas tree, you won't be able to yank it.
I'd convert the dots to tabs, then block select each column:
:%s/\./CtrlV-Tab/g
CtrlV to then block select the columns.
Or, as you'd have tab separated values, they will paste directly into columns in Excel.
At the top of the file:
!}awk -F. '{print $1}' >> %
You will be told the file has changed. Select the L (load) option.
Add a blank line under the original lines, go back to the top.
for(i=1;i<=NR;i++);print $2 >> %
Again select the L option
Delete the original lines.
You now have the first and second parts in two groups.
One possible solution:
w (or W for WORDS) jumps to next word,
CTRL-R CTRL-W gets the word under cursor and pastes it into command-line
Now you have to chain those commands in a loop and then output them in your own manner.
You can select columns in gvim by typing either Ctrl-VCtrl-G or Ctrl-QCtrl-G (depending on if you are using windows insert key mappings) and then selecting with the mouse.
nnoremap <BS> v"by:%!column -t -s<C-r>b -o' '<CR>
This is a nice solution following on from #NES & #SergioAraujo idea. Put it in your vimrc.
USAGE. Move the cursor to the delimiter. Then hit Backspace.
Explanation we use the named register b to hold our delimiter. Then substitute it as the variable for the --separator option of the column UNIX utility.
And Backspace is a good key because in normal mode is the same as h. But then again you might also be prone to hitting it accidentally.