How do I delete the last character in each line using vim - vim

I have a file:
12345a
123456b
1234567c
12345678d
123456789e
How do I delete the last character in each line.
And the file will be
12345
123456
1234567
12345678
123456789

You could use :%s/.\{1}$// to delete 1 character off the end of each line.

:%normal $x
: puts you into command line mode
% is a range representing the entire file
normal says we're running a normal mode command
$x deletes the last character in the line
Some overlap with other answers, but to me this one reads most simply.

TLDR: :%s/.$//
For explanation and more examples read on.
:%s/.$//
deletes any character at the end of all lines (or better to say: replaces any character at the end with nothing)
s = substitute command
. = any character
if you want to delete . (not any character) use \.$ instead of .$
:'<,'>s/.$//g
deletes any character at the end of all lines of the current selection
'<,'> = current selection (you get this by SHIFT+V, then selecting the lines, then :)
:%s/;$//
deletes ; at the end of all line
useful if you copy & paste code from a language that needs ; to one that doesn't

Use :g command:
:g/^/norm $x
^ matches every line which will be operated on.
norm is shorthand for normal, going before the normal command you want to execute.
$x move to the end of a line, and delete a character in normal mode

Related

Separate lines with blank lines in Vim?

I am dealing with a block of comments like:
//this is comment 1
//this is comment 2
//this is comment 3
//this is comment 4
I would like to make it look like:
//this is comment 1
//this is comment 2
//this is comment 3
//this is comment 4
Is there a Vim shortcut to make this transformation on selected lines while staying in command mode?
You can use the :substitute command. With the cursor anywhere on the
first of the lines:
:,+3s/$/\r
This inserts an additional newline at the end of each line.
You can also use the :global command. With the cursor anywhere on
the first of the lines, run:
:,+3g//norm o
For each of the next four lines, this executes the o Normal-mode
command, adding a new blank line.
In both of the commands, the ,+3 prefix is a range for the
command, see :help range. Briefly, the comma separates the addresses
of the starting and ending lines of the range, where the current line
is used if we omit the former of the two addresses. The +3 address
refers to the line that is three lines below from the current line.
Rather than specifying a range, e.g., ,+3, for either of these
commands, you can use the V Normal-mode command to make a Visual
block across all the lines that you want. Then typing : to begin the
command will auto-fill the range specifying the visual block, and you
can then enter either of the two commands starting with s or g:
:'<,'>s/$/\r
You can use a macro:
qao<esc>jq
then use 3#a to apply the macro 3 times over the last lines.
where:
qa "Start recording a macro named a
o "Insert new line under current line
<esc> "Exit insert mode
j " Move down next line
q " end macro
Select your visual selection with V
Then run a regex replace to replace one line break with two
:s/\n/\r\r/g
One can use the command
:g/^/pu_
on the whole buffer (by default) or on a selected range of lines.
Select the lines you want with V
Then type : and s/\ze/\r

Deleting to the beginning of line when line starts with whitespace characters

I usually use
d^ to delete to the beginning of line.
But if the line starts with space or tabulations, the deletion does not go all the way to start of line.
Example:
foo foo
The line starts with two spaces, and the cursor is between the two "foo"
d^ deletes the first foo, but not the two spaces before it.
It is obviously useful most of the time, but what if I do want to delete everything?
You can use d0 to delete to the real beginning of the line.
as #GWW mention and:
use c0 to delete to real begginning of the line and go insert mode.
c^ - delete to first non-blank character and go insert mode.
You can also use | to goto column 0 of a line, which can be using in combination with d as d| to delete to column 0 of a line.
Source: http://hea-www.harvard.edu/~fine/Tech/vi.html
If the cursor in the middle of an empty space between beginning of line and the first character of the line, then you can delete the whole spaces with diw, that means: delete inner word. In this case word is the spaces.

Cut and paste in Vim without moving next line up

When I cut and paste in VIM by pressing v, and go to the end of the line using $, and press d, the next line gets moved up to the same line I'm cutting.
How do I stop this?
It moves up because you have removed all the characters including line return/feed.
There are multiple solutions as usual with Vim. There is no "one true way" but you can try the following commands.
You can use D (capital) in normal mode which will erase everything until the end of line.
See :help D
Using another motion
What you could do instead of using $ to move to the end of the line, use g_. It will move to the last non blank character of the line and won't select line return.
See :help g_
So vg_d should work as you want.
Using Replace
Alternatively, what you could do instead of cutting, you could replace the erased character by a blank using the space character.
So v$rSPACE should work to erase but it will not save the replaced characters in register (for pasting later for example).
To cut everything from current cursor position until the end, use C.
:he C will help you:
Delete from the cursor position to the end of the
line and [count]-1 more lines [into register x], and
start insert. Synonym for c$ (not |linewise|).
Doing so will cause the current line (assuming you are on the start of the line when hitting C) to become empty and the content is (by default) yanked into register "
Edit:
As Xavier notes in his comment (and his answer), the same could be achieved with D. It also cuts everything from current cursor position until the end of the line but doesn't go in insert mode after doing it.
If you use these keystroke sequence then next line would not move up.
v $ h d
It is moving up because EOL character $ is also getting deleted without moving cursor 1 character back.
Just skip the visual mode and swap the other two commands, ie. press d $.
This is shorter than your starting one and doesn't break your tradition introducing other keystrokes you may not be familiar with.

Delete all text in line before/after highlighted search pattern

I know in VIM how to search a string and delete the text till the start/end of line but I would like to know if it is also possible to delete all text in line before or after highlighted search pattern.
If you want to do this across all lines and don't want to retype your search term I'd suggest the following:
:%s/.*\ze<Ctrl-r>///
What this does is:
%s/: substitute across all lines in a file
.*: match any character
\ze: end matching so the rest of the pattern is not substituted
<Ctrl-r>/: insert text from the '/' register (which is the search register)
//: replace with nothing
Edit: Forgot about the after part. My suggestion to remove both at the same time would be:
:%s/.*<Ctrl-r>/.*/<Ctrl-r>//
To delete the text before FOO on the same line:
:s/^.*\(FOO\)/\1/
From beginning of line to the beginning of highlighted search pattern: 0dn
From after end of highlighted search pattern to the end of line: $N//e<Enter>lD
These will work in most of the cases.
I can't comment on other answers, so I answer here, but I am referring to the answer from xofon:
Just add a '%' in the command line, which would make do for all lines in a file.
delete all chars after ']' in all lines
:%s/\(\]\).*$/\1/
delete all chars before ' -- ' in all lines in a file
:%s/^\( -- \).*/\1/
To delete all text in the line line both before and after the search match you could also do:
:g//norm gnd0PlD
This executes normal mode commands on all lines that match the last search pattern. The commands are gn to select the match, d to delete it, 0P to paste it at the beginning of the line, l to move to the left (after the text that was just pasted) and D to delete until the end of the line. I'm given to understand gn is a fairly recent addition to vim, so YMMV.

How to copy all hlsearch text to clipboard in Vim

file.txt
abc123
456efg
hi789j
command
:set hlsearch
/\d\+
I want to copy highlighted text bellow to clipboard (or register):
123
456
789
Just like
egrep -o '[0-9]+' file.txt
Thanks.
One can follow the below procedure.
Empty a register (for instance, "a).
qaq
or
:let #a = ''
Run the command1
:g/\d\+/norm!//e^Mv??^M"Ay
If it is necessary to append a new line character after each of the
matches, run this command instead:2
:g/\d\+/norm!//e^Ma^M^[??^Mv$"Ayu
Type ^M as Ctrl+V then Enter (or
Ctrl+M), type ^[ as
Ctrl+V then Esc (or
Ctrl+[). In order not to retype the pattern
that just have been used in search, one can press
Ctrl+R, / to automatically insert
last search pattern.
Also one can record the command to execute on matched lines (the part
following norm!) as a macro. This allows to see the actions
immediately on a sample line and to make sure they are correct. Then,
the macro can be applied using :global:
:g/\d\+/norm!#z
1 At the top level, the command is a :global executing the Ex
command norm!//e^Mv??^M"Ay on each of the lines that match the pattern
\d\+. The Ex command begins with the norm! command to execute the Normal
mode commands //e^Mv??^M"Ay. These are three commands separated by the
carriage return symbol ^M. The first one, //e, looks for the search
pattern (which is set to the pattern used in the global command) and put the
cursor to the last symbol of the match (because of the flag e, see :help
search-offset). Then v command starts Visual mode. The command ?? looks
for the last search pattern backwards (and put the cursor to the first
character of the match), thus selecting the text that match the last search
pattern. The last command, "Ay, yanks the selected text appending it to the
a register.
2 The second global command resembles the first one in outline.
At each of the matched lines, it moves cursor to the last symbol of the match
and inserts newline after that symbol. Then it puts the cursor to the start
of the match and selects (in Visual mode) everything up to the end of line
(including just inserted newline). Finally, the command appends the selected
text to the register, and undoes newline inserting.
3 One can always see the actions recorded in particular macro by
examining the contents of the corresponding register using :di z or "zp,
for example.
If your text obeys the pattern you posted you can start visual mode blockwise with Ctrl+V and select from 1 in the first line to 9 in the last line. Then you just copy to the + register, which is the system clipboard, by typing "+y.
Edit:
I have tested this new solution for the text:
abc123
456efg
hi789j
Replace all non-digit by nothing with :%s/\D//g and the result will be:
123
456
789
Copy it to the clipboard typing "+y%, then revert the changes with u and you are done.
Use this command to extract all URLs, and append to the end of file:
:let urls = [] | %s/http:[^"]*/\=add(urls, submatch(0))[-1]/g | call setline(line('$')+1, urls)

Resources