我只想将具有特定模式(例如;)的线连接在一起,但是当使用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


或类似的东西,所以包含该模式的所有行都连接在一起。

如何实现?

评论

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

#1 楼

问题的可能解释

我认为:g/;/j不起作用的原因是因为:g命令使用2-pass算法运行:


第一次遍历时,它标记包含模式;的行

,第二遍遍在标记的行上操作

在第二遍过程中,:g1;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


b可以进一步细分,例如:是Ex命令j的缩写形式,与大多数其他Ex命令一样,可以在其前面加上范围。
此处的范围之前::join.,/^[^;]*$/-1
范围遵循a,b的形式,其中a,ba通常是2行号,并且允许您在行号介于ba之间的一组行上进行操作,而不仅仅是一个。

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

:g/pattern/a,bj


#2 楼

我一直通过全局搜索进行类似的联接并替换:

s/;\n/;/


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

评论


仅s仅适用于一行,要使其成为全局行,您需要使用%s,但随后它将连接几乎所有行,包括non;线

– Kenorb
16年1月1日在20:39

@kenorb嗯,不,我认为您可以完全根据需要使用:s命令。我认为这%s /; \ n \(。*; \)\ @ = /; /可以满足您的需求。

–克里斯蒂安·布拉班特(Christian Brabandt)
16年1月1日在21:01

@Christian Brabandt您的解决方案%s /; \ n \(。*; \)\ @ = /; /可以正常工作,但是\ @ =是什么?

–马克
20年6月19日在16:19



@Mark我刚刚将您的答案转换为评论;在这样做时,我想指出的是,您可以使用:help以及几乎所有内容来获取更多建议。即使是简单的:help也非常有用。

– D. Ben Knoble♦
20年6月19日在19:36