我经常使用具有可变数量空格的文本文件作为单词分隔符(像Word这样的文本处理器执行此操作,以便在某些字体中由于不同大小的字母而公平地分配空白量,并且它们将这个令人讨厌的可变量即使以纯文本格式保存也是如此。
我想自动化用单个空格替换这些具有可变长度的空格序列的过程。我怀疑一个正则表达式可以做到这一点,但是在段落的开头还有空格(通常是四个,但并不总是),我想让它保持不变,所以基本上我的正则表达式也应该不触及前导空格这个增加了复杂性。
我正在使用vim,所以vim正则表达式方言中的正则表达式对我来说非常有用,如果这是可行的。
我目前的进展如下:
:%s/ \+/ /g
但它无法正常工作。
我也在考虑编写一个可以逐个解析文本行的vim脚本,用char处理每一行char并在第一行之后跳过空格,但我觉得这有点矫枉过正。
答案 0 :(得分:104)
这将替换2个或更多空格
s/ \{2,}/ /g
或者您可以在\+
之前为您的版本添加额外空格
s/ \+/ /g
答案 1 :(得分:59)
这样可以解决问题:
%s![^ ]\zs \+! !g
使用\zs
和\ze
元序列,可以比其他正则表达式方法更容易在Vim中完成许多替换。他们所做的是从最终结果中排除部分匹配,序列前的部分(\zs
,“s”表示“从这里开始”)或部分(\ze
,“e “for”end here“)。在这种情况下,模式必须首先匹配一个非空格字符([^ ]
),但是后面的\zs
表示最终匹配结果(将被替换的内容)在之后 em>那个角色。
由于无法在行前导空格前面放置非空格字符,因此模式不会匹配,因此替换不会替换它。简单。
答案 2 :(得分:37)
为了实用主义,我倾向于将其作为一个三阶段过程来实现:
:g/^ /s//XYZZYPARA/g
:g/ \+/s// /g
:g/^XYZZYPARA/s// /g
我不怀疑可能有更好的方法(可能使用宏或甚至纯正的正则表达方式)但我通常发现这在我匆忙时有用。当然,如果您的行以XYZZYPARA
开头,则可能需要调整字符串: - )
转好:
This is a new paragraph
spanning two lines.
And so is this but on one line.
成:
This is a new paragraph
spanning two lines.
And so is this but on one line.
旁白:如果您想知道为什么我使用
:g
代替:s
,那大多只是习惯。:g
可以完成:s
所能做的所有事情。它实际上是一种在选定行上执行任意命令的方法。在这种情况下执行的命令恰好是s
所以没有真正的区别,但是,如果你想成为一个vi
超级用户,你应该在某个时候调查:g
。 / p>
答案 3 :(得分:7)
这里有很多好的答案(特别是亚里士多德:\zs
和\ze
非常值得学习)。为了完整起见,您也可以使用负面的后顾断言来做到这一点:
:%s/\(^ *\)\@<! \{2,}/ /g
这表示“找到2个或更多空格(' \{2,}'
),前面没有'行的开头后跟零个或多个空格'”。如果您希望减少反斜杠的数量,也可以这样做:
:%s/\v(^ *)@<! {2,}/ /g
但它只能为您节省两个字符!如果您不介意进行多余的更改(即将单个空格更改为单个空格),也可以使用' +'
代替' {2,}'
。
您还可以使用负面后卫来检查单个非空格字符:
:%s/\S\@<!\s\+/ /g
与亚里士多德的略微修改版本相同,为了节省一些打字,将空格和制表符视为相同的一样):
:%s/\S\zs \+/ /g
请参阅:
:help \zs
:help \ze
:help \@<!
:help zero-width
:help \v
和(全部阅读!):
:help pattern.txt
答案 4 :(得分:2)
这有用吗?
%s/\([^ ]\) */\1 /g
答案 5 :(得分:2)
我喜欢这个版本 - 它类似于亚里士多德Pagaltzis的超前版本,但我发现它更容易理解。 (可能只是我对\ zs的不熟悉)
s/\([^ ]\) \+/\1 /g
或所有空白
s/\(\S\)\s\+/\1 /g
我把它读作“替换除了空格之外的所有事物,然后用一些东西和一个空格替换多个空格”。
答案 6 :(得分:2)
回答;但是,无论如何我都会投入我的工作流程。
%s/ / /g
@:@:@:@:@:@:@:@:@:@:@:@:(repeat till clean)
快速而简单的记忆。上面有一个更优雅的解决方案;但只是我的.02。