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?)

Was it helpful?

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 number
  • getline(line(".")-1) is the text of the previous line
  • strpart(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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top