2

I've been trying to select all characters except the last word (2 groups where 1 group is everything but the last word and the other group is only the last word)

:%s/^.\+\([^\w\+]$\)/\2\1/g

is what I have so far and I've been stuck.

  • 2
    you should add some sample lines to test.. for example, does your definition of word means alphabets only? or alphabets+numbers+underscore etc... also, if white-space is separator between words, how to deal with white-space at end of line and do you need to add white-space while re-arranging? – Sundeep Oct 16 '17 at 6:00
5
:%s/^\(.\+\)\s\+\(\S\+\)$/\2 \1/

The second pair of parens contains a continuous string of non-whitespace \S\+ (also known as a "WORD") preceding the end of the line.

The first pair of parens gobbles everything else except for some whitespace \s\+. This requirement of ending before some whitespace prevents it from greedily consuming the final WORD.

This ignores the whitespace between groups 1 and 2 and then reinserts a single space in the substitution. But we could also do three captures if you want to preserve the whitespace exactly (e.g. if it has tabs):

:%s/^\(.\+\)\(\s\+\)\(\S\+\)$/\3\2\1/

Let's make it more readable by using "very magic" mode:

:%s/\v^(.+)(\s+)(\S+)$/\3\2\1/

If a line is indented things get a little ugly. Optionally, we could preserve any indentation thusly:

:%s/\v^(\s*)(.+)(\s+)(\S+)$/\1\4\3\2/

Notes:

  1. I'm assuming that you want to preserve a sentence-like structure in the result (i.e. no space at the beginning that wasn't there before and always put space between the first and second word). If you don't want that use something like the first command above but remove the one space in the substitution.
  2. No trailing whitespace allowed, the line won't match so no substitution, but that can be handled by inserting \s* right before $ in the pattern.
  3. /g flag is not required as this pattern matches an entire line...only one substitution possible.
4

You've specified that you want to use regular expressions and back-references, but, depending on your precise requirements, it's arguably easier to achieve this without using regular expressions.

:%norm $diw0Pa<Space>

N.B. I've written <Space> above, as otherwise the space would be invisible: you should enter an actual space character by pressing your space bar once.

This does roughly the same thing as the first :substitute command in B Layer's answer and, because it just uses normal-mode commands, should be easy to understand for any Vim user:

  • :%norm: Run the following series of normal mode commands on every line,
  • $: Move to end of line; substitute g_ for $ if some of your lines end in whitespace,
  • diw: Delete inner word; substitute W for w if you want to move WORDs,
  • 0: Move to beginning of line; substitute ^ for 0 if you want to preserve indentation,
  • P: Put the word at the beginning of the line,
  • a<Space>: Add in a space.

If your file also contains blank lines, you can use :global to only run the :normal command on non-blank lines:

:g/\S/norm $diw0Pa<Space>

Further improvements are possible if you need more sophisticated handling of whitespace.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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