如何通过替代在Vim中在两个字符串之间包含至少n个空格?

问题描述 投票:3回答:2

我有一个文本文件,每行有两个长度不同的单词。为了更好地阅读,我希望每行的第二个单词前面都有足够的空格字符,以便与以下所有行中的第二个单词对齐。

例如,给定文本:

bla foo
barbla barfoo
foblaaaa Bablofoo

我想更改为:

bla      foo
barbla   barfoo
foblaaaa Bablofoo

是否可以通过Vim中的正则表达式(例如s/…/…/g)格式化文件?类似以下内容,

:s/^\(\w\+\)\s*\(.*\)$/\1\t\t\t\2/g

但是需要动态调整必要的空白量吗?

regex vim substitution
2个回答
1
投票

这可能不是正则表达式,因为您必须通过首先遍历文件然后开始包含空格来计算第一个单词的最大宽度。

如果您真的想像@Prince Goulash所建议那样避免使用Tabular,这是一个有趣且简单的解决方案:

let n = system("awk '{ if (length($1) > L) { L = length($1) }}; END { print L }' ".expand("%:p"))
%s/\s\+/\=repeat(' ', n+1-system("awk '{ print length($1) }'", getline('.')))

在第一行中,变量n将接收一个awk程序的输出。它基本上找到了第一个字段的最大宽度,这是第一个工作。请注意末尾的expand("%:p"):我们将文件扩展为完整路径,而不是简单地传递文件名,以免与当前目录混淆。

下一行是实际替换。它用表达式替换找到的第一组空白。表达式返回一串重复一定时间的空格,即n(最大宽度)减去当前行第一个单词的长度(再次求助!)加上一个缓冲区空间(您可以使用2或其他任何值)您想要的电话号码。

这将使所有内容对齐。


如果要安装Tabular,则打开缓冲区并运行:

:Tab / 

注意斜杠后有空格。

现在有一百万美元的问题:您要安装Tabular吗?


1
投票

在列中对齐文本的一种简单方法是使用TabularAlign插件。 As I have shown回答问题“ Inserting indentation for columns in Vim”,可以在帮助下仅使用内置Vim功能解决问题以下命令。1,2

:let m=0|g/\ze\>/let m=max([m,searchpos(@/,'c')[1]])
:%s//\=repeat(' ',m-col('.'))

第一个命令的目的是确定分隔符左侧的一列(我假设它是第一个字,\>)。宽度计算为最大所有行中第一列中的文本长度。的:global命令用于枚举包含分隔符(其他行不需要对齐)。 \ze原子位于图案开始位置之后设置在开始位置相同的位置进行匹配(请参见:help \ze)。改变中比赛的边界不会影响:global命令的方式的作品,这种模式是这样写的,以适应需求下一个替换命令:由于这两个命令可以共享相同的模式,该模式可以在第二个模式中省略。

在匹配的行上运行的命令,

:let m=max([m,searchpos(@/,'c')[1]])

调用searchpos()函数来搜索使用的相同模式在父项:global命令中,并获取比赛。使用上一次搜索将该模式称为@/模式寄存器(请参见:help "/)。这利用了事实:global命令尽快更新/寄存器开始执行。 c标志作为第二个参数传递给searchpos()调用允许在一行的第一个字符处进行匹配(:global将光标定位到在上执行命令),因为左侧可能没有文本分隔符。 searchpos()函数返回一个列表,第一个元素是匹配位置的行号,第二个是列的位置。如果命令在一行上运行,该行与包含的:global命令的模式匹配。如searchpos()是要寻找相同的模式,肯定有一个在那条线上匹配。因此,只有开始匹配的列是感兴趣的是,它由[1]从返回列表中提取下标。此位置等于文本中文本的宽度该行的第一列,再加上一个。因此,将m变量设置为其值和该列位置的最大值。

第二个命令,

:%s//\=repeat(' ',m-col('.'))

将分隔符的第一个出现填充在所有包含它,以及使文本缺少的空格数分隔符前取m字符,减一。这个命令是全局替换,用于替换之前的空间隔分隔符(请参见上面有关:global命令的注释)表达式求值的结果(请参见:help sub-replace-\=),

repeat(' ',m-col('.'))

repeat()函数重复其第一个参数(作为字符串),第二个参数中给出的次数。由于每个替换为将光标移动到模式匹配的开始,m-col('.')完全等于移位所需的空格数分隔符以使列对齐(col('.')返回光标的当前列位置。


1这对命令可以重写为单个命令:

:let m=0|exe'g/\ze\>/let m=max([m,searchpos(@/,"c")[1]])'|%s//\=repeat(' ',m-col('.'))

2其余文本复制了给出的详细说明在the aforementioned answer of mine中。

© www.soinside.com 2019 - 2024. All rights reserved.