0

The file contains only one line:
enter image description here

four_blank_space + "TE:" + one blank space + "trailers" + one blank space

I write a grouping replace:

:1s/\(\s\+\)\(.\+\):\s\+\(.\{-}\)\(\s\{0,}\)/\2/

I think that :

  • The first group \s\+ will match the four blank spaces at the beginning of the line.
  • The second group .\+ will match the string TE.
  • :\s\+ will match the string : between TE and trailers.
  • The third group .\{-} will match string trailers.
  • The last group \s\{0,} will match the last white space at the end of the line.

So replace the whole line with the second group, the output should be TE, but why the result is TEtrailers ?

enter image description here

3 Answers 3

0

The problem is not .+; it’s (.{-})(\s{0,}). Your pattern as written (my examples will all use \v) simply doesn’t match the whole line because the non-greedy match and the trailing space match are empty.

But \v\s+(.+):\s+.{-}\s+ or \v\s+(.+):\s+.+\s+ do, with the latter . repetitions working as intended because the space repetition was required to match at least once. This latter is effectively \v\s+(.+):.* if you aren’t using the other capture groups (which I’ve eliminated because I’m typing on mobile).

0

With :help 'incsearch' enabled, what is matched by the regular expression you are typing is highlighted for you in real time.

This means that you get a chance to get your patterns right before they are actually used.

In this case, highlighting makes it obvious that your troubles start at capture group #2:

sub

where you are combining a crude atom (.) with a greedy quantifier (\+), and thus effectively matching everything after the four leading spaces.

After that, it only goes downhill because you are mainly using subsequent atoms and capture groups for their side-effects on the previous ones. On one hand you are saving yourself some thinking with .\s but, on the other hand, you are forcing yourself to do complicated things in order to fight the problems it creates. A bit like being lazy and a workaholic at the same time.

A smarter approach would be to use more refined patterns. The following substitution does what you want with mush less effort.

:1s/\s\+\([^:]\+\).*/\1

where the more precise [^:]\+ doesn't extend beyond the : and thus allows us to finish lazily with .*.

2
  • Your explanation of the problem omits the latter half of the pattern, which affects what the original .+ will match (in particular, the colon forces .+ to stop, but the rest of the pattern matches empty and leaves a trailing string around during substitution).
    – D. Ben Knoble
    Commented Mar 10, 2023 at 14:44
  • It is omitted because it is irrelevant to the point I wanted to make. I will rewrite it to not confuse you and OP.
    – romainl
    Commented Mar 10, 2023 at 15:10
0

With very magic and non-greedy match and group:

1s/\v\s+(.{-}):\s+(.{-})\s+/\2/

It is more clear and readable in logic though a bit of logger than other expressions.

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.