Search and delete to end of line in vim - 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

Related

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.

Vim: delete empty lines around cursor

Suppose I'm editing the following document (* = cursor):
Lions
Tigers
Kittens
Puppies
*
Humans
What sequence can I use to delete the surrounding white space so that I'm left with:
Lions
Tigers
Kittens
Puppies
*
Humans
Note: I'm looking for an answer that handles any number of empty lines, not just this exact case.
EDIT 1: Line numbers are unknown and I only want to effect the span my cursor is in.
EDIT 2: Edited example to show I need to preserve leading whitespace on edges
Thanks
Easy. In normal mode, dipO<Esc> should do it.
Explanation:
dip on a blank line deletes it and all adjacent blank lines.
O<Esc> opens a new empty line, then goes back to normal mode.
Even more concise, cip<Esc> would roll these two steps into one, as suggested by #Lorkenpeist.
A possible solution is to use the :join command with a range:
:?.?+1,/./-1join!
Explanation:
[range]join! will join together a [range] of lines. The ! means with out inserting any extra space.
The starting point is to search backwards to the first character then down 1 line, ?.?+1
As the 1 in +1 can be assumed this can be abbreviated ?.?+
The ending point is to search forwards to the next character then up 1 line, /./-1
Same as before the 1 can be assumed so, /./-
As we are using the same pattern only searching forward the pattern can be omitted. //-
The command :join can be shorted to just :j
Final shortened command:
:?.?+,//-j!
Here are some related commands that might be handy:
1) to delete all empty lines:
:g/^$/d
:v/./d
2) Squeeze all empty lines into just 1 empty line:
:v/./,//-j
For more help see:
:h :j
:h [range]
:h :g
:h :v
Short Answer: ()V)kc<esc>
In normal mode, if you type () your cursor will move to the first blank line. ( moves the cursor to the beginning of the previous block of non-blank lines, and ) moves the cursor to the end (specifically, to the first blank line after said block). Then a simple d) will delete all text until the beginning of the next non-blank line. So the complete sequence is ()d).
EDIT: You're right, that deletes the whitespace at the beginning of the next non-blank line. Instead of d) try V)kd. V puts you in visual line mode, ) jumps to the first non-blank line (skipping the whitespace at the beginning of the line), k moves the cursor up one line. At this point you've selected all the blank lines, so d deletes the selection.
Finally, type O (capital O) followed by escape to crate a new blank line to replace the ones you deleted. Alternatively, replacing dO<Escape> with c<Escape> does the same thing with one less keystroke, so the entire sequence would be ()V)kc<Esc>.
These answers are irrelevant after the updated question:
This may not be the answer you want to hear, but I would make use of ranges. Take a look at the line number for the first empty line (let's say 55 for example) and the second to last empty line (perhaps 67). Then just do :55,67d.
Or, perhaps you only want there to ever be one empty line in your whole file. In that case you can match any occurrence of one or more empty lines and replace them with one empty line.
:%s/\(^$\n\)\+/\r/
This answer works:
If you just want to use normal mode you could search for the last line with something on it. For instance,
/.<Enter>kkVNjd
I didn't test so much, but it should work for your examples. There maybe more elegant solutions.
function! DelWrapLines()
while match(getline('.'),'^\s*$')>=0
exe 'normal kJ'
endwhile
exe 'silent +|+,/./-1d|noh'
exe 'normal k'
endfunction
source it and try :call DelWrapLines()
I know this question has already been resolved, but I just found a great solution in "sed & awk, 2nd Ed." (O'Reilly) that I thought was worth sharing. It does not use vim at all, but instead uses sed. This script will replace all instances of one or more blank lines (assuming there is no whitespace in those lines) with a single blank line. On the command line:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile
Keep in mind that sed does not actually edit the file, but instead prints the edited lines to standard output. You can redirect this input to a file:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile > tempfile
Be careful though, if you try to write it directly to myfile, it will just delete the entire contents of the file, which is clearly not what you want! After you write the output to tempfile, you can just mv tempfile myfile and tada! All instances of multiple blank lines are replaced by a single blank line.
Even better:
cat -s myfile > temp
mv temp myfile
cat is awesome, yes?
Bestest:
If you want to do it inside vim, you can replace all instances of multiple blank lines with a single blank line by using vim's handy feature of executing shell commands on a range of lines within vim.
:%!cat -s
That's all it takes, and your entire file is reformatted all nice!

Vim: substitution in a range that is less than a line

Let's say I have the following line of code:
something:somethingElse:anotherThing:woahYetAnotherThing
And I want to replace each : with a ; except the first one, such that the line looks like this:
something:somethingElse;anotherThing;woahYetAnotherThing
Is there a way to do this with the :[range]s/[search]/[replace]/[options] command without using the c option to confirm each replace operation?
As far as I can tell, the smallest range that s acts on is a single line. If this is true, then what is the fastest way to do the above task?
I'm fairly new to vim myself; I think you're right about range being lines-only (not 100% certain), but for this specific example you might try replacing all of the instances with a global flag, and then putting back the first one by omitting the global -- something like :s/:/;/g|s/;/:/.
Note: if the line contains a ; before the first : then this will not work.
Here you go...
:%s/\(:.*\):/\1;/|&|&|&|&
This is a simple regex substitute that takes care of one single not-the-first :.
The & command repeats the last substitute.
The | syntax separates multiple commands on one line. So, each substitute is repeated as many times as there are |& things.
Here is how you could use a single keystroke to do what you want (by mapping capital Q):
map Q :s/:/;/g\|:s/;/:<Enter>j
Every time you press Q the current line will be modified and the cursor will move to the next line.
In other words, you could just keep hitting Q multiple times to edit each successive line.
Explanation:
This will operate globally on the current line:
:s/:/;/g
This will switch the first semi-colon back to a colon:
:s/;/:
The answer by #AlliedEnvy combines these into one statement.
My map command assigns #AlliedEnvy's answer to the capital Q character.
Another approach (what I would probably do if I only had to do this once):
f:;r;;.
Then you can repeatedly press ;. until you reach the end of the line.
(Your choice to replace a semi-colon makes this somewhat comfusing)
Explanation:
f: - go to the first colon
; - go to the next colon (repeat in-line search)
r; - replace the current character with a semi-colon
; - repeat the last in-line search (again)
. - repeat the last command (replace current character with a semi-colon)
Long story short:
fx - moves to the next occurrence of x on the current line
; repeats the last inline search
While the other answers work well for this particular case, here's a more general solution:
Create a visual selection starting from the second element to the end of the line. Then, limit the substitution to the visual area by including \%V:
:'<,'>s/\%V:/;/g
Alternatively, you can use the vis.vim plugin
:'<,'>B s/:/;/g

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

Find first non-matching line in VIM

It happens sometimes that I have to look into various log and trace files on Windows and generally I use for the purpose VIM.
My problem though is that I still can't find any analog of grep -v inside of VIM: find in the buffer a line not matching given regular expression. E.g. log file is filled with lines which somewhere in a middle contain phrase all is ok and I need to find first line which doesn't contain all is ok.
I can write a custom function for that, yet at the moment that seems to be an overkill and likely to be slower than a native solution.
Is there any easy way to do it in VIM?
I believe if you simply want to have your cursor end up at the first non-matching line you can use visual as the command in your global command. So:
:v/pattern/visual
will leave your cursor at the first non-matching line. Or:
:g/pattern/visual
will leave your cursor at the first matching line.
you can use negative look-behind operator #<!
e.g. to find all lines not containing "a", use /\v^.+(^.*a.*$)#<!$
(\v just causes some operators like ( and #<! not to must have been backslash escaped)
the simpler method is to delete all lines matching or not matching the pattern (:g/PATTERN/d or :g!/PATTERN/d respectively)
I'm often in your case, so to "clean" the logs files I use :
:g/all is ok/d
Your grep -v can be achieved with
:v/error/d
Which will remove all lines which does not contain error.
It's probably already too late, but I think that this should be said somewhere.
Vim (since version about 7.4) comes with a plugin called LogiPat, which makes searching for lines which don't contain some string really easy. So using this plugin finding the lines not containing all is ok is done like this:
:LogiPat !"all is ok"
And then you can jump between the matching (or in this case not matching) lines with n and N.
You can also use logical operations like & and | to join different strings in one pattern:
:LP !("foo"|"bar")&"baz"
LP is shorthand for LogiPat, and this command will search for lines that contain the word baz and don't contain neither foo nor bar.
I just managed a somewhat klutzy procedure using the "g" command:
:%g!/search/p
This says to print out the non-matching lines... not sure if that worked, but it did end up with the cursor positioned on the first non-matching line.
(substitute some other string for "search", of course)
You can search with following line and press n to jump to the first non-matching line
^\(.*all is ok\)\#!.*$
Breakdown of operators:
^ -> means start of the line
\( and \) -> To match a whole string multiple times, it must be grouped into one item. This is done by putting "\(" before it and "\)" after it.
\#! -> Matches with zero width if the preceding atom does NOT match at the current position.
.* -> Matches any character repeated 1 or more times
$ -> end of the line
Here is sample animation how it works. For simplicity I searched for word apple.
You can iterate through the non-matches using g and a null substitution:
:g!/pattern/s/^//c
If you reply "n" each time you wont even mark the file as changed.
You need ctrl-C to escape from the circle (or keep going to bottom of file).

Resources