vim 嵌套单行循环中断命令

Posted

技术标签:

【中文标题】vim 嵌套单行循环中断命令【英文标题】:vim nested one-liner loop breaks command 【发布时间】:2022-01-14 16:34:53 【问题描述】:

我想为文件中的特定行多次附加一个字符,以便所有这些行都有 x 个字符

假设我希望 20 到 80 之间的所有行都具有相同数量的字符 (50) 并在末尾附加相同的字符:

for y in range(20, 80) | if strlen(getline(y)) !=50 | for i in range(50-strlen(getline(y))) | execute y .. 's/$/./' | endfor | endif | endfor

返回 E727:Start past endE1098: String, List or Blob required

如果我将它与特定行一起使用,它就可以正常工作 if strlen(getline(N)) !=50 | for i in range(50-strlen(getline(N))) | execute N .. 's/$/./' | endfor | endif

例如:

输入:

abcdef
defghijklm
foo

输出:

abcdef**********
defghijklm******
foo*************

【问题讨论】:

由于您只想更改特定的行号,因此您应该在示例中包含您不想更改的行。 【参考方案1】:

这些错误来自哪里?

E727: Start past end

这个错误是由range(50-strlen(getline(y)))中的公式50-strlen(getline(y))引起的,当y行的字符数大于50时,返回一个:help range()不喜欢的负数。

E1098: String, List or Blob required

此错误是前一个错误的结果:range(50-strlen(getline(y))) 不返回任何可以循环的内容,因此 :for 无法工作。

这些错误可能可以通过在“单行”中添加更多检查和分支来避免,但这似乎不是一个好主意,如果只是因为你的命令已经太复杂了,因为它所做的很少。

使用更简单的方法可以更可靠地实现预期结果:

:20,80s/$/\=repeat('*',50-strlen(getline('.')))
这是一个快速的:help :substitute,具有范围、模式和:help sub-replace-special 表达式。 20,80 是我们的范围,请参阅 :help :range$ 是我们的零宽度模式,行尾。 非常强大的\=<expr> 允许我们使用<expr> 返回的字符串作为替换。 :help repeat() 将给定的字符串重复给定的次数。 * 是我们的字符串。 重复次数使用您自己的公式计算。当行长超过 50 时,重复次数为负数,表示没有重复,因此该行没有附加 *

之前:

a short line
some filler text foo
a line with 59 characters dgsfdsjgdfsjdshdlsjdfshjdsfdlhsjd
what

之后:

a short line**************************************
some filler text foo******************************
a line with 59 characters dgsfdsjgdfsjdshdlsjdfshjdsfdlhsjd
what**********************************************

【讨论】:

【参考方案2】:

使用 GNU sed。先追加 16 个星,然后只保留前 16 个字符。

sed -E 's/$/****************/; s/(.16).*/\1/' file

输出:

abcdef********** defghijklm****** 富**************

【讨论】:

OP 说他们希望该行长度为 50 个字符,因此您需要输入更多 *s :-)。这是 sed 解决方案的明显问题,您无法对其进行编程以创建 50 个*s,您需要将它们输入(或调用 shell 脚本来生成它们)。【参考方案3】:

只需使用 awk,它就是为这样的工作创建的:

$ cat file
line 1
line 2
line 3
abcdef
defghijklm
foo
line 7
line 8

$ awk '
    BEGIN  wid=50; pad=sprintf("%*s",wid,""); gsub(/ /,"*",pad) 
    4<=NR && NR<=6  $0=substr($0 pad,1,wid) 
1' file
line 1
line 2
line 3
abcdef********************************************
defghijklm****************************************
foo***********************************************
line 7
line 8

更改宽度(50 以上)和开始/结束行号(4 和 6 以上)以适合。

【讨论】:

以上是关于vim 嵌套单行循环中断命令的主要内容,如果未能解决你的问题,请参考以下文章

用于在 python 中创建列表的单行非嵌套 for 循环

嵌套循环

使用 Itertools 具有内部中断的可变级别的嵌套循环

嵌套线程中断计时器[重复]

单行命令循环打印输出脚本

单行命令循环打印输出脚本