您可以将:s 命令与\= aka sub-replace-expression 结合使用。
:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&\').'\2','')#
概述
捕获>>> 和<<< 标记之间的文本(包括空格)。将文本两边的空白分成两半,并用中间的非空白文本替换。这种空白平衡行为是通过正则表达式引擎的回溯完成的,因为数学很难。我们去购物吧!
注意事项:
- 使用
\v 或very magic 模式来减少转义,因为此命令足够长
已经
- 使用
# 作为替代分隔符,而不是通常的/ 用于:s/pat/sub/,以使其更具可读性
匹配模式
:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#...
-
:s 没有提供范围,只在当前行进行替换。
-
^\s*\S+ 匹配起始空白,后跟非空白。 >>> 在这种情况下。
-
(\s+)(.{-})(\s+) 匹配空格后跟“文本”后跟空格
- 3 个捕获组:1) 前导空白,2) “文本”,以及 3) 尾随空白。稍后将分别由
submatch(1)、submatch(2) 和submatch(3) 引用
-
.{-} 是 vim-speak 用于非贪婪匹配或 .*? 在 perl-speak 中
- 如果没有非贪婪匹配,第二个捕获组将在其末尾包含太多空白
-
\S+\s*$ 匹配非空白(即<<<)和任何尾随空白
- 使用
\zs 和ze 指定要替换的比赛的开始和结束
替换
\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&\').'\2','')
-
\= 告诉 vim 替换将是一个 vim 表达式。还允许使用submatch() 函数
-
substitute({str}, {pat}, {sub}, {flags})我们的表达式将是一个嵌套替换
-
substitute(submatch(1).submatch(3), ...) 替换 submatch(1) 和 submatch(3) 中捕获的前导和尾随空白的串联
-
{pat} 是^(\s*)(\1\s=)$。匹配一些空格,后跟与第一个或 1 个字符长度相同的空格。捕获两半。
-
escape(submatch(2),'~&\') 转义 submatch(2) 用于任何特殊字符。例如~,&,\1, ...
-
{sub} 是'\1'.escape(submatch(2),'~&\').'\2'。替换为{pat} 的两半空白之间的转义submatch(2)(即我们想要居中的“文本”),\1 和\2
- 不需要
{flag},所以''
用法
如果您经常使用它,我建议您创建一个命令并将其放入~/.vimrc。
command! -range -bar -nargs=0 CenterBetween <line1>,<line2>s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.submatch(2).'\2','')#`
否则使用一次,然后在每个需要的行上通过& 重复最后一次替换。
有关更多帮助,请参阅
:h :s/
:h :s/\=
:h sub-replace-\=
:h submatch(
:h substitute(
:h escape(
:h /\v
:h /\S
:h /\{-
:h /\zs
:h &
肯特编辑
别嫉妒,你的答案也有。 ^_^
我没有更改命令,只是 cp/paste 到我的 vim。仅在末尾添加|noh 以禁用突出显示。
如果执行这个命令,它看起来像: