How to delete the last word from each line in vim? - vim

Please let me know, How I can remove the last word from each line using vim commands?
Before :
abcdef 123
xyz 1256
qwert 2
asdf 159
after :
abcdef
xyz
qwert
asdf
Similarly please let me know how to remove the second word from each line using vim command?

Use the following regex (in ex mode):
%s/\s*\w\+\s*$//
This tells it to find optional whitespace, followed by one or more word characters, followed by optional whitespace, followed by end of line—then replace it with nothing.

The question's been answered already, but here's what I'd more likely end up doing:
Record a macro:
qq to record a macro into register "q"
$ to go to the end of the line
daw to delete a word
q to stop recording
Then select the rest of the lines:
j to go down a line
vG to select to the end of the file
And apply the macro:
:norm #q
Some similar alternatives:
:%norm $daw
qq$dawjq (note the added j) then 999#q to replay the macro many times. (Macro execution stops at the first "error" -- in this case, you'd probably hit the bottom of the file, j would not work, and the macro would stop.)

The key for this is the :substitute command; it is very powerful (and often used in vi / Vim).
You need to come up with a regular expression pattern that matches what you want to delete. For the last word, that's whitespace (\s), one or more times \+ (or any number (*), depending on how you want to treat single-word lines), followed by word characters (\w\+), anchored to the end of the line ($). Note that word has a special meaning in Vim; you may want to use a different atom (e.g. \S). Voila:
:%s/\s\+\w\+$//
For the second word, you can make use of the special \zs and \ze atoms that assert for matches, but do not actually match: Anchored at the start (^), match a word, then start the match for a second one:
:%s/^\w\+\s\+\zs\w\+\s\+//
Soon, you'll also want to reorder things, not just remove them. For that, you need to know capturing groups: \(...\). The text matched by those can then be referred to in the replacement part. For example, to swap the first and second words:
:%s/^\(\w\+\s\+\)\(\w\+\s\+\)/\2\1/
For details, have a look at the help, especially :help :substitute and :help pattern.

To remove the second word from the start of a line, use the following:
:%s/^\(\s*\w\+\s\+\)\w\+\s*/\1/
Update
To treat special characters as part of the word, you have to use the \S (which matches all non-whitespace characters) instead of \w (which matches only word characters [0-9A-Za-z_]). Then, the command would be:
:%s/^\(\s*\S\+\s\+\)\S\+\s*/\1/

Related

Search and delete to end of line in vim

I am trying to clean up some code and I am trying to find a good way of achieving the following:
I am a #decent
guy
and I want:
I am a guy
I tried using
:g/#/d
but the whole line gets deleted and I only want to delete until the end of line. What is the best way to achieve this in vim?
Thank you.
That won't because the usage of that command:
:[range]g/pattern/cmd
defaults to range being the whole line, and you are not doing any substitution anyway.
Use:
:%s/#.\+\n//g
instead.
# Matches a literal #.
.\+\n Matches everything until the end of line, and a new line.
// Replaces the entire match with nothing.
With :global you would want something like
:global/#/normal! f#D | join
or
:global/#/substitute/#.*// | join
Try this instead:
:s/ # .*\n/ /
Explanation:
You were using the wrong command, as they may look similar to new users.
:[range]g/VRE/act Globally apply the "act"ion (one letter command) to all lines (in range, default all file) matching the VRE (pattern)
:[range]s/VRE/repl/f Substitute within lines (in range, default current line) the matching VRE (pattern) with the "repl"acement using optional "f"lags
Now about the pattern, I think this candidate cover most cases (all but comments at the beginning of a line and comments without space after pound sign)
# litteral space, then hash tag, then space again
.* dot for any character, star to mean the previous may occur many times or even be absent
$ dollar at end to stay at "end of line", but \n to catch en EOL here
press d + shift 4 or d + $, which means delete to end of the line
d means delete
shift 4 or $ means cursor to end of the line

How to find and remove part of word in vim?

I'm new into vim, I have hug text file as follow:
ZK792.6,ZK792.6(let-60),cel-miR-62(18),0.239
UTR3,IV:11688688-11688716,0.0670782
ZC449.3b,ZC449.3(ZC449.3),cel-miR-62(18),0.514
UTR3,X:5020692-5020720,0.355907
First, I would like to get delete all rows with even numbers (2,4,6...).
Second, I would like to remove (18) from entire file. as a example:
cel-miR-62(18) would be cel-miR-62.
Third: How can I get delete all parentheses including it's inside?
Would someone help me with this?
For the first one:
:g/[02468]\>/d
where :g matches all lines by the regex between the slashes and runs d (delete line) on the matching lines. The regex is quite easy to read, the only interesting symbol there is perhaps the \>, which matches end of a word.
For the second question:
:%s/\V(18)//g
where % is the specification meaning "all lines of the file", s is the substitute command, \V sets the "very nomagic" mode of regexes (not sure what your default is, you might not need this) and the final g makes vim substitute all occurrences on each line (with an empty string, the one between slashes). Make sure that :set gdefault? prints nogdefault (the default setting of gdefault), otherwise, drop the final g from the substitute command.
To remove every even line (or every other line):
:g/^/+d
To remove every instance of (18):
:%s/(18)//g
Remove all the parenthetical content:
:%s/(.\\{-})//g
Note: the pattern in third answer is a non-greedy match.

How to replace in vim

I have a line in a source file: [12 13 15]. In vim, I type:
:%s/\([0-90-9]\) /\0, /g
wanting to add a coma after 12 and 13. It works, but not quite, as it inserts an extraspace [12 , 13 , 15].
How can I achieve the desired effect?
Use \1 in the replacement expression, not \0.
\1 is the text captured by the first \(...\). If there were any more pairs of escaped parens in your pattern, \2 would match the text capture between the pair starting at the second \(, \3 at the third \(, and so on.
\0 is the entire text matched by the whole pattern, whether in parentheses or not. In your case this includes the space at the end of your pattern.
Also note that [0-90-9] is the same as [0-9]: each [...] collection matches just one character. It happens to work anyway, because in your data ‘a digit followed by a space’ matches in the same places as ‘2 digits followed by a space’. (If you actually needed to only insert commas after 2 digits, you could write [0-9][0-9].)
"I have a line in a source file:..."
then you type :%s/... this will do the substitution on all lines, if it matched. or that is the single line in your file?
If it is the single line, you don't have to group, or [0-9], just :%s/ \+/,/g will do the job.
The fine answers already point interesting solutions, but here's another one,
making use of the \zs, which marks the start of the match. In this pattern:
/[0-9]\zs /
The searched text is /[0-9] /, but only the space counts as a match. Note
that you can use the class \d to simplify the digit character class, so the
following command shall work for your needs:
:s/\d\d\zs /, /g ; matches only the space, replace by `, '
You said you have multiple lines and these changes are only to certain lines.
You can either visually select the lines to be changed or use the :global
command, which searches for lines matching a pattern and applies a command to
them. Now you'd need to build an expression to match the lines to be changed
in a less precise as possible way. If the lines that begins with optional
spaces, a [ and two digits are the only lines to be matched and no other
ones, then this would work for you:
:g/\s*[\d\d/s/\d\d\zs /, /g
Check the help for pattern.txt for \ze and similar and
:global.
Homework: use the help to understand \zs and see how this works:
:s/\d\d\zs\ze /,/g

How do I remove the last six characters of every line in Vim?

I have the following characters being repeated at the end of every line:
^[[00m
How can I remove them from each line using the Vim editor?
When I give the command :%s/^[[00m//g, it doesn't work.
You could use :%s/.\{6}$// to literally delete 6 characters off the end of each line.
The : starts ex mode which lets you execute a command. % is a range that specifies that this command should operate on the whole file. The s stands for substitute and is followed by a pattern and replace string in the format s/pattern/replacement/. Our pattern in this case is .\{6}$ which means match any character (.) exactly 6 times (\{6}) followed by the end of the line ($) and replace it with our replacement string, which is nothing. Therefore, as I said above, this matches the last 6 characters of every line and replaces them with nothing.
I would use the global command.
Try this:
:g/$/norm $xxxxxx
or even:
:g/$/norm $5Xx
I think the key to this problem is to keep it generic and not specific to the characters you are trying to delete. That way the technique you learn will be applicable to many other situations.
Assuming this is an ANSI escape sequence, the ^[ stands for a single <Esc> character. You have to enter it by pressing Ctrl + V (or Ctrl + Q) on many Windows Vim installations), followed by Esc. Notice how this is then highlighted in a slightly different color, too.
It's easy enough to replace the last six characters of every line being agnostic to what those characters are, but it leaves considerable room for error so I wouldn't recommend it. Also, if ^[ is an escape character, you're really looking for five characters.
Escape code
Using ga on the character ^[ you can determine whether it's an escape code, in which case the status bar would display
<^[> 27, Hex 1b, Octal 033
Assuming it is, you can replace everything using
:%s/\%x1b\[00m$//gc
With \%x1b coming from the hex value above. Note also that you have to escape the bracket ([) because it's a reserved character in Vim regex. $ makes sure it occurs at the end of a line, and the /gc flags will make it global and confirm each replacement (you can press a to replace all).
Not escape code
It's a simple matter of escaping then. You can use either of the two below:
:%s/\^\[\[00m$//gc
:%s/\V^[[00m\$//gc
If they are all aligning, you can do a visual-block selection and delete it then.
Otherwise, if you have a sequence unknown how to input, you can visually select it by pressing v, then mark and yank it y (per default into register "). Then you type :%s/<C-R>"//g to delete it.
Note:
<C-R>" puts the content of register " at the cursor position.
If you yanked it into another register, say "ay (yank to register a - the piglatin yank, as I call it) and forgot where you put it, you can look at the contents of your registers with :reg.
<C-R> is Vim speak for Ctrl+R
This seems to work fine when the line is more than 5 chars long:
:perldo $_ = substr $_, 0, -5
but when the line is 5 or less chars long it does nothing.
Maybe there is a easy way in perl to delete the last 5 chars of a string, but I don't really know it:)
Use this to delete:
:%s/^[[00m//gc

Vim: delete until character for all lines containing a pattern

I'm learning the power of g and want to delete all lines containing an expression, to the end of the sentence (marked by a period). Like so:
There was a little sheep. The sheep was black. There was another sheep.
(Run command to find all sentences like There was and delete to the next period).
The sheep was black.
I've tried:
:g/There was/d\/\. in an attempt to "delete forward until the next period" but I get a trailing characters error.
:g/There was/df. but get a df. is not an editor command error.
Any thoughts?
The action associated with g must be able to act on the line without needing position information from the pattern match that g implies. In the command you are using, the delete forward command needs a starting position that is not being provided.
The problem is that g only indicates a line match, not a specific character position for it's pattern match. I did the following and it did what I think you want:
:g/There was/s/There was[^.]*[.]//
This found lines that matched the pattern There was, and performed a substitution of the regular expression There was[^.]*[.] with the empty string.
This is equivalent to:
:1,$s/There was[^.]*[.]//g
I'm not sure what the g is getting you in your use case, except the automatic application to the entire file line range (same as 1,$ or %). The g in this latter example has to do with applying the substitution to all patterns on the same line, not with the range of lines affected by the substitution command.
I'd just use a regex:
%s/There was\_.\{-}\.\s\?//ge
Note how \_. allows for cross-line sentences
You can use :norm like this:
:g/There was/norm 0weldf.
This finds lines with "There was" then executes the normal commands 0weldf..
0: go to beginning of line
w: go to next word (in this case, "was")
e: go the end of the word (so cursor is on the 's' of "was")
l: move one character to the right (so we don't delete any of "was")
df.: delete until the next '.', inclusive.
If you want to keep the period use dt. instead of df..
If you don't want to delete from the beginning of the line and instead want to do sentences, the :%s command is probably more appropriate here. (e.g. :%s/\(There was\)[^.]*\./\1/g or %s/\(There was\)[^.]*\./\1./g if you want to keep the period at the end of the sentence.
Use search and replace:
:%s/There was[^.]*\.\s*//g

Resources