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 end
和 E1098: 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 嵌套单行循环中断命令的主要内容,如果未能解决你的问题,请参考以下文章