tags:

views:

376

answers:

3

I have a file with about 1000 lines. All lines begin with a seven-digit number except for the occasional line. I need to catch these lines and actually join them with the previous line.

I've managed to be able to match any line that begins with a seven-digit number by using the following regex pattern:

^\d\{7}

I can't seem to get it to match any line that does not match this pattern though, which is really what I'm after.

As a second question that I'll embed into this one. Is it possible to have any lines that match (or do not match to stay consistent with what I'm trying to do) to join themselves to the previous line (as opposed to the J command that brings the next line up to the current one)?

Thanks

+9  A: 
^\(\d\{7}\)\@!

This is vim's regex syntax for a negative lookahead.

If you're doing this as a mass : command, you should be able to just do

:v/^\d\{7}/-1j
chaos
Perfect thank you very much.
Jason Down
The second one worked great for what I need. Thanks again.
Jason Down
That command should be `:v/^\d\{7}/-1j`
rampion
Ah, yeah. Edited.
chaos
Oddly enough, they are both resulting in the same thing. Though to me it doesn't make sense that the one without the ^ is actually working, no that I think about it.
Jason Down
The only difference is that the one without the ^ will match if there is a seven-digit number somewhere else on the line other than the beginning.
chaos
Ah, yes I see. In this case there wasn't, so no extra lines were modified... explains why the count for fewer lines was exactly the same.
Jason Down
The :v/^\d\{7}/-1j command does not work for me: some of the "good" lines were joined with "bad" lines; and the joined lines has a space in between.
Hai Vu
@Hai Vu: I think you're misunderstanding what it's doing. It's joining the previous line to the seven-digit-number line, regardless of what that previous line is. The space between is the standard behavior of the `j` (join) command, though that can be tweaked.
chaos
And the space is actually something I wanted. So the solution works for what I need perfectly.
Jason Down
@chaos - I see. Thanks for the clarifications. That means my solution is wrong because I misunderstood the question. Duh!
Hai Vu
+2  A: 

The regexp

^\(\d\{7}\)\@!

will invert your original expression. For more info on this syntax, see here:

:help \@!

As for the second problem, you could for example replace the trailing newline on the previous lines with nothing:

:%s/$\n^\(\d\{7}\)\@!//g
tobiasvl
This one was close, but the join from the other answer left a space between the lines that were joined together (which is actually what I need). This example puts the last character from the first line directly before the first character from the next line. This is a side effect I need to avoid. Still, +1 for your answer and thank you.
Jason Down
Oh well! The space can be added like this though: :%s/$\n^\(\d\{7}\)\@!/ /g
tobiasvl
True enough. The other one is shorter though and I'm lazy ;P
Jason Down
+1  A: 

Here is my solution using awk, which can be called inside vim:

$ cat seven.awk
# Script to join lines that does not start with 7 digits
/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9]/ { print; next }
{ printf $0; getline; print }

$ cat seven.txt
123
4579 bad
7654321 This line is OK
1234567 OK So is this
111
2222 bad again
4443333 OK again

$ awk -f seven.awk seven.txt
1234579 bad
7654321 This line is OK
1234567 OK So is this
1112222 bad again
4443333 OK again

Please excuse my clumsy expression: my awk is old and it does not understand fancy expression like: \d{7}. If you want to invoke this command from inside vim for the entire file:

:%!awk -f seven.awk
Hai Vu
I originally had [0-9] seven times as well. I was quite pleased that the ex editor in gVim allowed the \d{7} shortcut.
Jason Down