【问题标题】:An easy way to center text between first and last non-white word in vim?在vim中将第一个和最后一个非白色单词居中的简单方法?
【发布时间】:2013-03-27 20:08:51
【问题描述】:

有没有一种简单的方法使用宏或 ~10 行函数(没有插件!)在一行的第一个和最后一个单词(=非空白字符的序列)之间居中一些文本?例如。转身

        >>> No user serviceable parts below.               <<<

进入

        >>>       No user serviceable parts below.         <<<

通过平衡 +/-1 的空间?您可以假设没有制表符,结果不应包含制表符,但请注意,第一个单词可能不在第 1 列中开始。(编辑:...事实上,分隔符单词以及文本的开头和结尾都居中可以在任意列上。)

【问题讨论】:

  • 有固定宽度吗?
  • @jacobwalker0814 没有固定宽度。 romainl:我试过:help center 并寻找插件,但对于这样一个简单的任务,插件似乎有点过头了。
  • @romainl 我曾想过使用外部过滤器程序,例如编写 perl 单行程序,但是当应该有 vim 内部解决方案时,这并不优雅。

标签: vim macros center


【解决方案1】:

获取此功能:

fun! CenterInSpaces()
    let l   = getline('.')
    let lre = '\v^\s*\S+\zs\s*\ze'
    let rre = '\v\zs\s*\ze\S+\s*$'
    let sp  = matchstr(l,lre)
    let sp  = sp.matchstr(l,rre)
    let ln  = len(sp)
    let l   = substitute(l,lre,sp[:ln/2-1],'')
    let l   = substitute(l,rre,sp[ln/2:],'')
    call setline('.',l)
endf

注意

  • 此功能可能适用于所有情况。我只是为通常的情况快速写了它。毕竟这不是插件

  • 可以通过组合函数调用来减少代码行。但是我觉得这样就清楚了,所以就这样放着吧。

  • 如果它适合您,您可以创建地图

  • 它的工作原理是这样的:(最后两行我输入了@: 以重复 cmd 调用)

【讨论】:

  • 太棒了。你是如何生成 gif 的?
  • 太棒了,而且只有 9 行 :-)
  • 分配给sp 的两个getline('.') 调用能否替换为l
  • @Jens你说得对,我只是cp/paste,不用想太多,我会修复它
  • 我也喜欢你的 gif。我有点嫉妒我的答案没有。
【解决方案2】:

您可以将: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','')#

概述

捕获&gt;&gt;&gt;&lt;&lt;&lt; 标记之间的文本(包括空格)。将文本两边的空白分成两半,并用中间的非空白文本替换。这种空白平衡行为是通过正则表达式引擎的回溯完成的,因为数学很难。我们去购物吧!

注意事项:

  • 使用\vvery magic 模式来减少转义,因为此命令足够长 已经
  • 使用# 作为替代分隔符,而不是通常的/ 用于:s/pat/sub/,以使其更具可读性

匹配模式

:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#...
  • :s 没有提供范围,只在当前行进行替换。
  • ^\s*\S+ 匹配起始空白,后跟非空白。 &gt;&gt;&gt; 在这种情况下。
  • (\s+)(.{-})(\s+) 匹配空格后跟“文本”后跟空格
  • 3 个捕获组:1) 前导空白,2) “文本”,以及 3) 尾随空白。稍后将分别由submatch(1)submatch(2)submatch(3) 引用
  • .{-} 是 vim-speak 用于非贪婪匹配或 .*? 在 perl-speak 中
  • 如果没有非贪婪匹配,第二个捕获组将在其末尾包含太多空白
  • \S+\s*$ 匹配非空白(即&lt;&lt;&lt;)和任何尾随空白
  • 使用\zsze 指定要替换的比赛的开始和结束

替换

\=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),'~&amp;\') 转义 submatch(2) 用于任何特殊字符。例如~,&amp;,\1, ...
  • {sub}'\1'.escape(submatch(2),'~&amp;\').'\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','')#`

否则使用一次,然后在每个需要的行上通过&amp; 重复最后一次替换。

有关更多帮助,请参阅

: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 以禁用突出显示。

如果执行这个命令,它看起来像:

【讨论】:

  • +1 我没有注意到这个答案。不错的替代品。顺便说一句,我为您制作了一个 gif 图像。将编辑您的答案并尽快添加,如果您不喜欢,请将其删除。 :)
  • 谢谢。总有一天我必须学会如何制作这些 gif。
  • 你不必学习,只是一个小工具。 google byzanz,你会看到,真的好用。
  • 圣洁的饼干真好吃!可悲的是,我在这里工作时使用窗户。谢谢你的提示
【解决方案3】:

我不知道有什么好办法。我通常以半自动方式执行此操作,即在仅包含要居中的部分的文本行上使用:center,然后将结果移动到包含周围部分的行中。

如果没有其他人有更好的答案,如果您经常需要做这种事情,也许boxes 可以提供帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    • 2010-12-15
    • 2013-06-13
    • 2011-06-08
    • 2015-04-03
    • 1970-01-01
    相关资源
    最近更新 更多