在vim的第n列之后对齐文本,删除不必要的空格

时间:2016-10-13 14:14:32

标签: vim

在vim中,在Windows机器中(无法访问" unix"类似命令这样的命令列)我想重新格式化这段代码以使其更具可读性:

COLUMN KEY_ID       FORMAT 9999999999
COLUMN VALUE_1                           FORMAT 99
COLUMN VALUE_2                            FORMAT 99
COLUMN VALUE_3              FORMAT 999
COLUMN VALUE_4        FORMAT 999

我希望尽可能减少使用此命令:

COLUMN KEY_ID      FORMAT 9999999999
COLUMN VALUE_1     FORMAT 99
COLUMN VALUE_2     FORMAT 99
COLUMN VALUE_3     FORMAT 999
COLUMN VALUE_4     FORMAT 999

请注意,这只是一个摘录,因为还有更多行我必须这样做。

4 个答案:

答案 0 :(得分:4)

您可以使用以下命令:

:%s/\w\zs\s*\zeFORMAT/^I

该模式将匹配FORMAT与前一个单词结尾之间的空格,并将其替换为标签:

\w      Any 'word' character
\zs     Start the matching
\s*     Any number of whitespace
\ze     End the matching
FORMAT  The actual word format

\zs\ze仅允许在空白处应用替换,请参阅::h /\zs:h /\ze

请注意^I应插入 ctrl + v 标签

@SatoKatsura推荐的tabular plugin也是一个很好的方法。

你也可以概括一下。我们假设你有以下文件:

COLUMN KEY_ID           FORMAT 9999999999
COLUMN VALUE_1                      FOO 99
COLUMN VALUE_2      BAR 99

您可以使用此命令:

:%s/^\(\w*\s\)\{1}\w*\zs\s*\ze/  

模式可以像这样详细说明:

^                 Match the beginning of the line
\(\w*\s\)\{1}     One occurrence of the pattern \w*\s i.e. one column
\w*               Another column
\zs\s*\ze         The whitespaces after the previous column

您可以更改\{1}的值以在下一列上应用命令。

编辑回答@aturegano评论,这是将列与另一列对齐的方法:

%s/^\(\w*\s\)\{1}\w*\zs\s*\ze/\=repeat(' ', 30-matchstrpos(getline('.'), submatch(0))[1])

我们的想法仍然是匹配必须对齐的空格,在替换命令的第二部分,我们使用子替换表达式(参见:h sub-replace-expression)。

这允许我们使用来自替换部分的命令,可以这样解释:

\=                 Interpret the next characters as a command
repeat(' ', XX)    Replace the match with XX whitespaces

XX is decomposed like this:
30-                 30 less the next expression
matchstrpos()[1]    Returns the columns where the second argument appears in the first one
getline('.')        The current line (i.e. the one containing the match
submatch(0)         The matched string
[1]                 Necessary since matchstrpos() returns a list:
                       [matchedString, StartPosition, EndPosition]
                    and we are looking for the second value.

然后,您只需将30替换为要移动下一列的列。

请参阅:h matchstrpos():h getline():h submatch()

答案 1 :(得分:2)

对于对齐,有三个众所周知的插件:

答案 2 :(得分:2)

按要求发布答案:

:g/^COLUMN / s/.*/\=call('printf', ['%s %-30s %s %s'] + split(submatch(0)))/

说明:

  • g/^COLUMN / - 将以下命令应用于与/^COLUMN /匹配的行(参见:h :global
  • \= - 替换为评估表达式的结果,而不是使用固定字符串(参见:h s/\=
  • submatch(0) - 匹配的行
  • split(...) - 将行拆分为单词
  • printf(...) - 格式化
  • call(...) - 我们希望printf('%s %-30s %s %s', list),但printf()不会将“真实”列表作为参数,因此我们必须以{{1}展开列表(参见call(...))。

答案 3 :(得分:0)

又一个解决方案:

:%s/ \{2,}/   /g

此解决方案并不完美,因为结果将在第一行上有额外的单个空格。要解决此问题:

:%s/\%>15c \{2,}/   /g

模式说明:

%>15c\s\{2,}

%>15c                 Matches only after column 15

     \s\{2,}          Matches two or more white spaces