如何将所有线匹配的模式匹配在一起?


11

我只想将具有特定模式(例如;)的行连接在一起,但是使用时g/;/j,除非多次调用,否则无法正常工作。

例如以下内容:

a
1;
2;
3;
4;
5;
b
6;
7;
8;
9;
c

使用时::g/;/j输出为:

a
1; 2;
3; 4;
5; b
6; 7;
8; 9;
c

:g/;/-j给出:

a 1; 2; 3; 4; 5;
b 6; 7; 8; 9;
c

与:类似:g/;\_.\{-};/j

我的预期输出是:

a 
1; 2; 3; 4; 5;
b
6; 7; 8; 9;
c

或类似的内容,因此包含该模式的所有线都连接在一起。

如何做到这一点?


3
FWIW :g/;/j不起作用,因为它分两步完成:首先扫描缓冲区,然后将命令应用于匹配的行。
romainl

Answers:


12

问题的可能解释

我认为:g/;/j不起作用的原因是该:g命令使用2遍算法进行操作:

  • 在第一遍中,它标记了包含模式的行 ;
  • 在第二遍中,它在标记的行上运行

在第二遍过程中,由于在第一遍过程中被标记,因此与line :g连接1;起来。但是我怀疑(不确定)它不加入,因为该行不再存在,它的内容已经与已经处理过的行合并了。 2;1;1; 2;3;2;1;

因此,:g寻找在第一遍(3;)期间标记的下一行,并将其与下一个(4;)连接起来。之后,问题再次出现3; 4;5;因为该行4;不再存在,因此无法加入。

解决方案1(带vimscript)

也许只要;找到包含的行,就可以调用函数来检查前一行是否也包含分号:

function! JoinLines()
    if getline(line('.')-1) =~ ';'
        .-1join
    endif
endfunction

然后使用以下全局命令:

:g/;/call JoinLines()

或没有功能:

:g/;/if getline(line('.')-1) =~ ';' | -j | endif

解决方案2(无vimscript)

:g/;/.,/^[^;]*$/-1j

每当全局命令:g找到模式时,;它都会执行命令: .,/^[^;]*$/-1j

可以这样分解:

:g/pattern/a,bj

哪里:

pattern = ;
a       = .           = number of current line
b       = /^[^;]*$/-1 = number of next line without any semicolon minus one

b 可以进一步细分如下:

/    = look for the number of the next line matching the following pattern
^    = a beginning of line
[^;] = then any character except a semicolon
 *   = the last character can be repeated 0 or more times
 $   = an end of line
 /   = end of pattern
 -1  = removes one to the number you just got

j是Ex命令的缩写形式:join,与大多数其他Ex命令一样,它可以以范围开头。
这里它是由前面范围:.,/^[^;]*$/-1a,b
甲范围如下的形式a,b,其中ab通常是2个号,并允许在一组线,其数量是之间的操作ab,而不是仅仅一个。

因此,该j命令将当前一个(a)和下一个不包含任何分号减一个(b)的下一行之间的所有行连接起来。

有关更多信息,请参见:

:help :global
:help :join
:help :range

1

我一直通过全局搜索和替换来进行类似的加入:

s /; \ n /; /

\n 匹配换行符。

查找和删除空白行:

s / ^ $ \ n //

我不确定为什么,但是如果要插入新行,则必须使用 \r


s单独将只适用于一条线,要使其成为全局线,您需要使用%s,但是它将加入几乎所有线,包括非;线
kenorb

2
@kenorb嗯,不,我认为您可以根据需要使用该:s命令。我认为这%s/;\n\(.*;\)\@=/;/可以满足您的需求。
Christian Brabandt '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.