1

I have some text like this.

    a x="true" i q={1}

That is, a line of text prefixed with 4 space characters. Then letters with spaces in between.

I'd like to transform the text to this

    a
x="true"
i
q={1}

(So keep the 4 spaces at the beginning and replace every next space with a line break.)

First, I tried s/ /\r/g, but then I realized that substitution also replaces the leading 4 spaces. However, I want to keep the 4 leading spaces.

Is there a way to use substitutions on parts of lines, instead of whole lines?

3
  • For that specific example this seems like an easy route: :s/a /a\r/g...or if the letters can be other than 'a'... `:s/\w /&\r/g'
    – B Layer
    Commented Feb 4, 2020 at 4:52
  • Ooh, cool. Didn't know about \w and &!
    – 425nesp
    Commented Feb 4, 2020 at 5:09
  • 1
    They're both pretty common, especially \w...do yourself a favor and read sections 4,5,6 in the pattern.txt reference (:h pattern). So many goodies.
    – B Layer
    Commented Feb 4, 2020 at 5:12

1 Answer 1

2

Jump to the end for the simplest solution. I decided to thumb my nose at the KISS principle for a while before snapping out of it and posting the easy answer. :P

At least three ways come to mind to handle this.

The first uses the %v pattern "atom" (see :h /\%v). This is used to pin the search after/before a column number. For example this matches all text up to column 17: /^.*\%17v

We'll use it to skip over the opening four spaces and then substitute line feeds for every space afterwards:

s/\%>4v /\r/g

Another option is to use "look arounds". Specifically a "negative lookbehind" (:h /\@<!). We want to change all spaces to line feed except for those that are at the beginning of the line or separated from the beginning of the line by only whitespace.

s/\%(^\s*\)\@<!\s/\r/g

So that says to match any whitespace, \s, as long as there is no match preceding it (\@<!) made up of the beginning of the line plus optional whitespace characters (\%(^\s*\)). This actually will work for any length of opening indent.

Note that lookaround expressions don't actually consume any of the target string. This explains: /zero-width

These answers are specifically targeting your stated use case (four-space indent followed by the "sentence" to modify). But the subject asks a more general question ("apply substitution on parts of lines"). That question has been asked before and you can find some more generalized discussion there: How to run a substitute command on only a certain part of the line

In fact, to understand my third solution I recommend you read my answer there. This approach is probably overkill for the relatively simple problem we're looking at here (though I maintain this isn't as complicated as some folks make it out to be). For the sake of thoroughness I give you the sub-replace expression solution:

s/^\s\+\zs\(.*\)/\=substitute(submatch(0), ' ', '\r', 'g')/

Update: Silly me, I left out the easiest solution. This despite the fact that I posted something similar in a comment above (though that was targeting an earlier, easier version of the question)...

s/\(\S\+\) /\1\r/g

That is, match every sequence of non-whitespace characters (\S\+) followed by a space (). Surround all but the space in a capturing group (\(...\)). Each occurrence of this pattern in the line will be replaced with the captured characters (\1) and then a line feed (\r).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.