我在文件中有一个行号列表,例如
1
5
3
我想向另一个文件中的每个行号添加相同的注释:
test1 # comment
test2 # comment
test3
test4
test5 # comment
有没有一种方法可以将文件逐行作为vim中行号的输入,并对其执行一些操作?我知道如何使用
定位单行5,5s/$/ # comment/
但是我不知道如何从文件中获取行号到vim命令中。
答案 0 :(得分:5)
您可以从文件创建Vim列表:
let list = readfile('path/to/list.txt')
或者如果文件已经在Vim中打开:
let list = getbufline('list.txt', 1, '$')
这会让您:
:echo list
['1', '5', '3']
第二步,我们需要找到适用的行。 for
循环将完成;行号将通过:execute
插入:
for l in list
execute l . 's/$/ # comment/'
endfor
或者,我们可以将:global
命令误用于迭代。不过,这要慢一些,对于index()
,我们必须避免将苹果(此处:数字行)与橙子(此处:字符串)分别表示清单)。我仍然提到这一点,因为这更笼统。例如您可以使用它从文件到目标行读取单词或正则表达式:
global/^/if index(list, "" . line('.')) != -1 | s/$/ # comment/ | endif
答案 1 :(得分:4)
听起来像Awk的工作。
:%!gawk 'NR == FNR {a[$0] = " \#comment"; next} FNR in a { $0 = $0 a[FNR]} 1' lines.txt -
awk程序已扩展以提高可读性:
NR == FNR {
a[$0] = " #comment";
next
}
FNR in a {
$0 = $0 a[FNR]
}
1
基本思想是我们将两个文件发送到awk中,分别为lines.txt
和stdin(-
)。我们在lines.txt
文件中将行号存储在数组a
中,并将注释作为值(a[$0] = " #comment";
)。如果行号在我们的数组(stdin
)内,则在经过FNR in a
时更新行。然后打印出stdin
(1
)的每一行
注意:我正在使用gawk
,因此您的里程可能会有所不同。还必须转义,#
,因为Vim会将其扩展到备用缓冲区。
答案 2 :(得分:3)
鉴于已完成列表的提取-请参阅Ingo的答案。
如果您没有太多的行和索引,则以下内容应该足够快(应该比:global
解决方案更快)
:call setline(1, map(range(1, max(list)), 'index(list, v:val) >=0 ? printf("test%d # comment", v:val) : v:val'))
如果行数和索引数增加很多,我不确定此O(N²)解决方案是否会扩展。由于:for
循环的速度很慢,因此我不确定使用现有工具可以如何高效地进行下去。
可能是:
:let d = {}
:call map(copy(list), 'extend(d, {v:val: printf("test%d # comment", v:val)})')
:call setline(1, map(range(1, max(list)), 'get(d, v:val, v:val)'))
这是绝对复杂的
以下是另一种复杂的O(N)方法
:call sort(list)
:call setline(1, map(range(1, slist[-1]), 'v:val == slist[0] ? printf("test%d # comment", remove(slist, 0)) : v:val'))
答案 3 :(得分:3)
您还可以使用生成的sed
脚本:
sed 's:$:s/$/ # comment/:' line_nums | sed -f- infile
生成的脚本如下:
1s/$/ # comment/
5s/$/ # comment/
3s/$/ # comment/
第二个sed
的输出如下所示:
test1 # comment
test2
test3 # comment
test4
test5 # comment