9

I have a text file which looks like this:

A.
text
text
text


A.
more text

more text

A.
more text

I want to join all lines between the "markers" A. so that it looks like:

A.texttexttext
A.more textmore text
A.more text

How can I do this in Vim?

3 Answers 3

5
:%s/\n\(\(A\.$\)\@!.*\)/\1/

Substitute a pattern matching:

  1. newline,
  2. a group containing of

    1. not the string A. directly followed by end-of-line, then
    2. any character until end of line

with:

  • everything matched except the starting newline (i.e. the group above),

and do this globally.

8
  • 1
    Thanks. I have no idea how that thing works, but it seems to! I will have to dissect it carefully. I also found a work around by joining all the lines and then inserting a new line on "A."
    – vim noob
    May 4, 2012 at 13:40
  • @vimnoob: See :help \@! in Vim for more info on that part. Otherwise it's straight forward, hopefully, with my explanation. A problem with your approach is that if "A." occurs in the text, though not as an isolated marker line, it will be split upon as if it were originally a marker. In practice it might not be a problem (I don't know what your "real" file looks like), but generically it can cause unwanted behavior if one is not aware of this. May 4, 2012 at 13:45
  • @vimnoob: I read my answer again, and in case you're not familiar with the :%s/// syntax: it's a "search and replace" syntax in Vim. : starts the command, % specifies the whole buffer as the range, s starts a substitution. / is the pattern delimiter (any other character can be used, but / is "standard"). The first / starts the search pattern, the second the replace pattern, and the third ends it. Trailing modifiers are available to specify case insensitivity, etc. \1 represents the grabbed group in the search pattern. :%s/foo/bar/ replaces foo with bar in the file. May 4, 2012 at 16:02
  • Thanks a lot for your help. I just need to research this \@! part as I am familiar with the basic search replace and basic regexp.
    – vim noob
    May 7, 2012 at 11:08
  • 1
    @Reman: The most straight-forward way I immediately think of is running a subsequent global pattern match like :%s/^A\.//. The method in the answer does not capture the ^A\. patterns themselves (rather their absence), so it cannot modify those strings in an obvious way. Nov 12, 2015 at 15:25
7

This also works (when the first line starts with A.)

:v/^A/-1j!
3
  • That does work! Nice. +1
    – ZaSter
    Mar 13, 2013 at 23:55
  • Yay, verily, and two tricks new to me, after the global anti-pattern match (v): the 'j' for join, and the '!' for join without adding a space. Thank you.
    – fortboise
    Nov 20, 2014 at 18:30
  • @Miro wow! i salute you sir. if you could explain why it works then super!.. also i had to concatenate the lines with tab character in between... so what i did was to add a s/$/\t/g tab characterat end of every line before issuing above command.. any better way
    – ihightower
    Jan 13, 2017 at 4:35
1

A more general solution that also works with more more complex input

$s/$/A./ | g/A./,/A./- s/\n\(A\.\)\@!//
$s/A\.$//
  1. insert missing A. at end of file
  2. Delete all newlines in between tags A.
  3. Delete the closing A. tag at the end of file
    *I Had to run this in e separate command, otherwise vim executed it before it had removed newlines. Can probably be solved somehow.

Input

B.
Don't join


A.
text
text
text


A.
more text

more text

A.
more text

Output

B.
Don't join


A.texttexttext
A.more textmore text
A.more text

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.