Question
How can I replace the first ten characters of a line where those ten characters match a particular pattern with the first ten characters from the line above?
Edit: It wasn't clear if I was asking to replace the first ten characters where the match could appear anywhere within the line, so maybe make a note in your answer if it deals with this case (call this case B and the intended one case A?)
Solution
Prehaps:
:%s/^\(.\{10}\)\(.*\n\)abcdefghij\(.*\)/\1\2\1\3/
Where 'abcdefghij' is the 10 character string on the 2nd line
OTHER TIPS
Something like this would work:
%s/^.\{10\}/\=strpart(get(getbufline("", line(".")-1), 0, ""), 0, 10)/
where ^.\{10\}
is your actual pattern.
%s/ # substitute all lines matching…
^.\{10\} # your pattern
/ # …with…
\= # an expression:
strpart( # gets the part of a string
get( # gets an element of a list
getbufline( # gets a list of lines from the current buffer
"", line(".")-1) # getbufline() the line before the current line
, 0, "") # get() first line in buffer, default to ""
, 0, 10) # strpart() first ten characters
/ # …end of substitution
:2,$g/<pattern>/s/^.\{10}/\=strpart(getline(line(".")-1),0,10)
2,$
is our range (as the first line has no previous line)g//
lets you run a command on lines that match a given pattern.s/^.\{10}/
will replace the first 10 characters of a line\=
lets you substitute the result of a vim expression in an:s//
line(".")
is the current line numbergetline(line(".")-1)
is the text of the previous linestrpart(getline(line(".")-1),0,10)
is the first 10 characters of the previous line
For example 2,$g/frog/s/^.\{10}/\=strpart(getline(line(".")-1),0,10)
will change:
I like eating mangos before frying frogs legs I wish I had a puppy She gave Dad a frog
To this:
I like eating mangos I like eating frogs legs I wish I had a puppy I wish I had a frog
If I have a complex action like that I usually record a macro using the q
command. Something like (untested):
/<pattern>
qq
10x
k
10yl
j
P
n
q
And then repeatedy issue that macro as @q
optionally prefixed with a count.
You could use search and replace:
:7,9 s/foo/bar/c
This example searches from line 7 to 9 for each occurrence of 'foo', and replaces it with 'bar', asking for a confirm on each hit. If you don't want to confirm, drop the c at the end. Pick the range as you see fit and this should get you where you want
Using only vim's motions and yanking/pasting.. Given the file contents of..
1234567890abcdef
qwertyuiopasdfgh
With the cursor on q, 10x
, file becomes:
1234567890abcdef
asdfgh
Move the cursor to the first line (using k
will do it), then do 10yl
(yank 10 characters, right)
Then move back down one line, j
, and paste P
(upper case, to paste under cursor) and the file becomes:
1234567890abcdef
1234567890asdfgh
In short, starting with the cursor on q:
10xk10yljP
..which you could paste in, or assign to a macro
It would be shorter if there was an obvious shortcut to paste by overwriting, but I couldn't find such a thing
One other option is an incredibly obscure looking regex search/replace..
Visual-line select the two target lines, and run the following search-and-replace:
:'<,'>s/\(\(.\{10\}\).*\)\n\(.\{10\}\)\(.*\)$/\1\r\2\4/
Basically it grabs..
\1
- the entire first line\2
- the first 10 characters (in a nested group)- a linebreak
\3
- the first ten characters of line two\4
- the rest of the second line
Then it constructs the two lines as \1\n\2\4
- complete first line, linebreak, first 10 characters of first, remainder of second