vim - delete everything between tab characters - vim

I have a file that has tab separated data. I need to delete 2 columns. So, what command(s) can I use to delete everything from the current tab to the next tab?

To delete columns 4 and 5:
:%s/^\(.\{-}\t\)\{3}\zs.\{-}\t.\{-}\t//
Explanation:
^ => start of line
.\{−} => as few characters as possible
\( .\{-}\t \)\{3} => three times as few characters as possible followed with a tab
\zs => start of match
It could be clearer with the \v switch:
:%s/\v^(.{-}\t){3}\zs.{-}\t.{-}\t//

I think shift+ctrl+v is what you are looking for.
http://jvi.sourceforge.net/javahelpset/jvi-vis_block.html

Does this have to be done in vim? If you have a unix command line I'd go instead for the good old cut command. For example the following will keep the first column, and everything including & after the 4th (discards 2 & 3)
cat filename | cut -d"\t" -f1,4- > outputfile

While you can use regular expressions, it is better to use simple f or t normal commands: when you are at the first character of the first column you want to delete d2f<Tab> will delete this and next columns unless one column can include newline in it. If it can, then d2/<Tab>/e<CR> (or d2/\t/e<CR>) will do what you want. To expand it on other lines, use macros: qaqqa01f<Tab>d2t<Tab>j#aq#a:
qaq: clear a register (starts recording a macros that will be stored in a register and then immediately stops recording before typing anything else);
qa: start recording a macros in register a;
0: go to the very beginning of the line;
1f<Tab>: jump to next tab. 1 may be omitted here. If you want to delete first column, then omit the whole motion;
d2t<Tab>: delete to second next tab;
j: move to next line;
#a: run macros stored in register a. It is empty at this point (because it was cleared in 1st item), so nothing is actually done;
q: stop recording a macros;
#a: run macros stored in register a. It contains items 3.-7. and in 7th item it will run itself.

:%s:\t[^\t]\+\t:\t\t:
This deletes everything between two tabs.
HTH

Related

How to complete the whole list with Vim?

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.

Using gvim, to copy few lines and paste them at the start of each line [duplicate]

I’d like to merge two blocks of lines in Vim, i.e., take lines k through l and append them to lines m through n. If you prefer a pseudocode explanation: [line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)].
For example,
abc
def
...
123
45
...
should become
abc123
def45
Is there a nice way to do this without copying and pasting manually line by line?
You can certainly do all this with a single copy/paste (using block-mode selection), but I'm guessing that's not what you want.
If you want to do this with just Ex commands
:5,8del | let l=split(#") | 1,4s/$/\=remove(l,0)/
will transform
work it
make it
do it
makes us
harder
better
faster
stronger
~
into
work it harder
make it better
do it faster
makes us stronger
~
UPDATE: An answer with this many upvotes deserves a more thorough explanation.
In Vim, you can use the pipe character (|) to chain multiple Ex commands, so the above is equivalent to
:5,8del
:let l=split(#")
:1,4s/$/\=remove(l,0)/
Many Ex commands accept a range of lines as a prefix argument - in the above case the 5,8 before the del and the 1,4 before the s/// specify which lines the commands operate on.
del deletes the given lines. It can take a register argument, but when one is not given, it dumps the lines to the unnamed register, #", just like deleting in normal mode does. let l=split(#") then splits the deleted lines into a list, using the default delimiter: whitespace. To work properly on input that had whitespace in the deleted lines, like:
more than
hour
our
never
ever
after
work is
over
~
we'd need to specify a different delimiter, to prevent "work is" from being split into two list elements: let l=split(#","\n").
Finally, in the substitution s/$/\=remove(l,0)/, we replace the end of each line ($) with the value of the expression remove(l,0). remove(l,0) alters the list l, deleting and returning its first element. This lets us replace the deleted lines in the order in which we read them. We could instead replace the deleted lines in reverse order by using remove(l,-1).
An elegant and concise Ex command solving the issue can be obtained by
combining the :global, :move, and :join commands. Assuming that
the first block of lines starts on the first line of the buffer, and
that the cursor is located on the line immediately preceding the first
line of the second block, the command is as follows.
:1,g/^/''+m.|-j!
For detailed explanation of this technique, see my answer to
an essentially the same question “How to achieve the “paste -d '␣'”
behavior out of the box in Vim?”.
To join blocks of line, you have to do the following steps:
Go to the third line: jj
Enter visual block mode: CTRL-v
Anchor the cursor to the end of the line (important for lines of differing length): $
Go to the end: CTRL-END
Cut the block: x
Go to the end of the first line: kk$
Paste the block here: p
The movement is not the best one (I'm not an expert), but it works like you wanted. Hope there will be a shorter version of it.
Here are the prerequisits so this technique works well:
All lines of the starting block (in the example in the question abc and def) have the same length XOR
the first line of the starting block is the longest, and you don't care about the additional spaces in between) XOR
The first line of the starting block is not the longest, and you additional spaces to the end.
Here's how I'd do it (with the cursor on the first line):
qama:5<CR>y$'a$p:5<CR>dd'ajq3#a
You need to know two things:
The line number on which the first line of the second group starts (5 in my case), and
the number of lines in each group (3 in my example).
Here's what's going on:
qa records everything up to the next q into a "buffer" in a.
ma creates a mark on the current line.
:5<CR> goes to the next group.
y$ yanks the rest of the line.
'a returns to the mark, set earlier.
$p pastes at the end of the line.
:5<CR> returns to the second group's first line.
dd deletes it.
'a returns to the mark.
jq goes down one line, and stops recording.
3#a repeats the action for each line (3 in my case)
As mentioned elsewhere, block selection is the way to go. But you can also use any variant of:
:!tail -n -6 % | paste -d '\0' % - | head -n 5
This method relies on the UNIX command line. The paste utility was created to handle this sort of line merging.
PASTE(1) BSD General Commands Manual PASTE(1)
NAME
paste -- merge corresponding or subsequent lines of files
SYNOPSIS
paste [-s] [-d list] file ...
DESCRIPTION
The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character,
and writes the resulting lines to standard output. If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
it were an endless source of empty lines.
Sample data is the same as rampion's.
:1,4s/$/\=getline(line('.')+4)/ | 5,8d
I wouldn't think make it too complicated.
I would just set virtualedit on
(:set virtualedit=all)
Select block 123 and all below.
Put it after the first column:
abc 123
def 45
... ...
and remove the multiple space between to 1 space:
:%s/\s\{2,}/ /g
I would use complex repeats :)
Given this:
aaa
bbb
ccc
AAA
BBB
CCC
With the cursor on the first line, press the following:
qa}jdd''pkJxjq
and then press #a (and you may subsequently use ##) as many times as needed.
You should end up with:
aaaAAA
bbbBBB
cccCCC
(Plus a newline.)
Explaination:
qa starts recording a complex repeat in a
} jumps to the next empty line
jdd deletes the next line
'' goes back to the position before the last jump
p paste the deleted line under the current one
kJ append the current line to the end of the previous one
x delete the space that J adds between the combined lines; you can omit this if you want the space
j go to the next line
q end the complex repeat recording
After that you'd use #a to run the complex repeat stored in a, and then you can use ## to rerun the last ran complex repeat.
There can be many number of ways to accomplish this. I will merge two blocks of text using any of the following two methods.
suppose first block is at line 1 and 2nd block starts from line 10 with the cursor's initial position at line number 1.
(\n means pressing the enter key.)
1. abc
def
ghi
10. 123
456
789
with a macro using the commands: copy,paste and join.
qaqqa:+9y\npkJjq2#a10G3dd
with a macro using the commands move a line at nth line number and join.
qcqqc:10m .\nkJjq2#c

Remove everything but the first column in VIM

I have a text file and I want to remove every word except the first word on every line and I have no idea how to do this.
So, if I have:
one two three
four five
six
I want to remain with:
one
four
six
Got any ideas?
If the lines don't start with whitespace, you could replace ' .*' (which matches everything after the first word) with an empty string:
:%s/ .*//g
A more robust solution is to filter it through a program that is really good at these kinds of manipulations: awk.
Say you had this content:
one two three
four five
six
Run :%!awk '{print $1}' and you will get:
one
four
six
awk's default field separator character is a space, though you could change it to whatever you wanted, depending on what you needed.
Alternatively, you can do it using a macro.
Type qa in normal mode to start recording a macro in register a.
Then type 0elDj to delete everything on the current line but the first word, and go to the next line.
Type q again to end recording the macro.
Now you can fire the macro on any line with #a.
Run :%norm! #a to apply the macro to every line in the buffer.
This way you can repeat any complex operation you want, not just substituting.
I love macros :)
EDIT: Note that it doesn't work when a line has strictly less than 2 characters. For this reason, this is generally not the best approach to this problem.

Macro for making numbered lists in vim?

Often times it seems I have a list of items, and I need to add numbers in front of them. For example:
Item one
Item two
Item three
Which should be:
1. Item one
2. Item two
3. Item three
In vim, I can press I in edit mode, insert "1.", hit escape. Then I go to the next line, press ., and then ^A to increment the number. This seems hugely inefficient... how would I make a macro so that I can go to the next line, and insert a number at the beginning which is one greater than the line before?
You can easily record a macro to do it.
First insert 1. at the start of the first line (there are a couple of spaces after the 1. but you can't see them).
Go to the start of the second line and go into record mode with qa.
Press the following key sequence:
i # insert mode
<ctrl-Y><ctrl-Y><ctrl-Y> # copy the first few characters from the line above
<ESC> # back to normal mode
| # go back to the start of the line
<ctrl-A> # increment the number
j # down to the next line
q # stop recording
Now you can play back the recording with #a (the first time; for subsequent times, you can do ## to repeat the last-executed macro) and it will add a new incremented number to the start of each line.
Select your lines in visual mode with: V, then type:
:'<,'>s/^\s*\zs/\=(line('.') - line("'<")+1).'. '
Which is easy to put in a command:
command! -nargs=0 -range=% Number <line1>,<line2>s/^\s*\zs/\=(line('.') - <line1>+1).'. '
Here's an easy way, without recording a macro:
Make a blockwise, visual selection on the first character of each list item:
^<C-V>2j
Insert a 0. at the beginning of these lines:
I0. <Esc>
Re-select the visual selection (which is now all of the 0s) with gv and increment them as a sequence g<C-A>:
gvg<C-A>
The entire sequence: ^<C-V>2jI0. <Esc>gvg<C-A>.
A recording of the process in action.
There are also some plugins for doing this type of work if you have to do it on occasion:
http://vim.sourceforge.net/scripts/script.php?script_id=670
You can use the 'record' feature.
It is an easy way to record macros in Vim.
See :help record
In normal mode 'qa' to start recording what you type in the 'a' register
Type the necessary command to insert a number at the beginning of line, copy it to next line and use CTRL-A to increase its value.
'q' to end the recording
then '#a' to replay the macro stored in register 'a'
('##' repeat the last macro).
And you can do things like '20#a' to do it twenty times in a row.
It is pretty handy to repeat text modification.
Depending of the cases, it is easier or harder to use than a regexp.
Maybe it's not a macro solution, but at least it's easy.
add numbers to all lines
It's possible to use :%!nl -ba or :%!cat -n commands which will add line numbers to all the lines.
On Windows, you've to have Cygwin/MSYS/SUA installed.
add numbers to selected lines
To add numbers only for selected lines, please select them in visual mode (v and cursors), then when finished - execute the command: :%!nl (ignore blank lines) or :%!cat -n (blank lines included).
formatting
To remove extra spaces, select them in visual block (Ctrl+v) and remove them (x).
To add some characters (., :, )) after the numbers, select them in visual block (Ctrl+v), then append the character (A, type the character, then finish with Esc).
Insert a number at the start of the block of text eg.
1. Item One
Enter the vim normal mode command as follows:
qb^yW+P^<Ctrl-A>q
This means:
qb # start recording macro 'b'
^ # move to start of text on the line
yW # 'yank' or copy a word including the ending whitespace.
+ # move one line down to the start of the next line
P # place text ahead of the cursor
^ # move to start of text
<Ctrl-A> # increment text
q # Finish recording macro
What this allows you to do is replay the macro across the last line of numbered list as many times as needed.
It is some time later and I think it is time to upgrade this answer, at least for neovim users.
Here I wrote a lua function you can bind to Enter and it will work on any imaginable type of list, such as
1. foo
1.99-> bar
and after pressing enter, this line will be added:
1.100->
all using this function
vim.api.nvim_set_keymap('i','<Enter>','v:lua.enter_or_list()', {expr = true})
function _G.enter_or_list()
local line = vim.api.nvim_buf_get_lines(0, vim.fn.line('.') - 1, -1, false)[1]:match('^%s*[^%a%s]+')
if not line then
return '\r'
else
local start, finish = line:find('[^%a%s]*%d')
local main = line:sub(start,finish)
local suffix = line:sub(finish+1)
return table.concat({
'\r',
main,
vim.api.nvim_replace_termcodes('<Esc><C-a>a', true, true, true),
suffix,
' '
})
end
end
for vim users, I have a little simpler, but a little less capable keybinding:
imap <silent> <S-Enter> <CR><Esc>kk<End>Ev<Home>yjpk<End>e<C-a><End>a<Space>
I hope this will be useful to other people as well, as it is very convenient.
Cheers

Align columns in VI

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.

Resources