Regex 用递增的数字替换每个匹配项
我需要在JSON文件中的对象列表中添加一个ID属性。我发现了有用的内联Perl脚本,它将每个匹配项替换为一个随机整数Regex 用递增的数字替换每个匹配项,regex,perl,vim,Regex,Perl,Vim,我需要在JSON文件中的对象列表中添加一个ID属性。我发现了有用的内联Perl脚本,它将每个匹配项替换为一个随机整数 :%! perl -pne 's/XYZ/int(rand 1000)/ge' 假设我事先不知道列表的长度,我将如何替换这样的内容 { "id" : XYZ }, { "id" : XYZ }, { ... } 为此: { "id" : 1 }, { "id" : 2 }, { ... } 我试过这个: :%! perl -pne 's/XY
:%! perl -pne 's/XYZ/int(rand 1000)/ge'
假设我事先不知道列表的长度,我将如何替换这样的内容
{
"id" : XYZ
},
{
"id" : XYZ
},
{ ... }
为此:
{
"id" : 1
},
{
"id" : 2
},
{ ... }
我试过这个:
:%! perl -pne 's/XYZ/(0..100)/ge'
但这是假设我提前知道列表的长度,并且也不能像预期的那样工作。我知道我可以用这样的方法获得许多匹配项:
:%s/"id" : XYZ//gn
-p
已经逐行处理输入,因此-n
是冗余的
perl -pe 's/XYZ/$i++/ge'
$i++
在数字上下文中返回$i
的值,并向其添加1。使用Perl(在5.14+中),您不需要处理可能出现在其他地方的字符串,不管字符串和数字是否应该被引用,或者其他复杂的问题,您只需将JSON作为数据结构进行修改即可(可能需要修改代码以修改完整JSON结构的正确部分):
更好的方法是使用,因为默认情况下安装和使用更快的解析器
-0777
开关是一个用于一行程序的开关,用于使readline或
操作符(也由-p开关使用)立即返回整个输入。如果您在Vim中执行此操作,并且您有+perl
那么:
:%perldo s/XYZ/++$i/e
如果您想使用普通的Vim命令来执行,您可以按照
使用相同的逻辑和变量。但是,它需要
预先创建,每次替换后递增。
因此,您可能需要:g
的帮助来执行两个命令:
:let i=0
:g/XYZ/let i+=1|s//\=i
空的s/
重用:g
中的模式
或者,只需像您所做的那样通过Perl对其进行过滤
原来:
:%!perl -pe 's/XYZ/++$i/e'
对于那些寻找纯Vim解决方案的人,这里有一个比@sidyll的答案更规范、更一般的解决方案,它不需要
:perldo
或:global
,也可以在一行中使用多个匹配项(将g
标志添加到:substitute
):
内置替代品
在Vim中,您可以使用任意表达式替换文本。不幸的是,变量递增在Vim中是一个语句,而不是一个表达式。任何一个都必须使用一些技巧,例如使用列表的长度作为计数器(add()
可以在表达式中使用):
或者您必须定义一个单独的函数(一次):
带插件
表达式语法有点奇怪(但是如果你喜欢Perl,你习惯了更糟糕的情况:-)很麻烦。My通过几个变体改进了内置的:substitute
命令。其中:SubstituteExecute
,它得益于预定义的上下文对象:
:%SubstituteExecute /XYZ/ let v:val.n += 1 | return v:val.n
重新编号是如此频繁的任务,以至于插件甚至有一个特殊的命令:
:Renumber /XYZ/
警告
- 结构化但灵活的语法(如HTML或JSON)不适合使用正则表达式进行解析,除非您确信所使用的允许语法子集是非常规则的(例如,因为您知道输入源和/或通过漂亮的打印机传递了输入)。与通用工具相比,您更喜欢专用工具(即,对于XML使用
,对于JSON使用xmlstarlet
,而不是jq
和grep
)sed
+$i
?@zdim:我不确定OP想在哪里开始:0..100
似乎在0开始。啊,对了……我正在查看所需的输出。不管怎样,adetail@ikegami:我测试了代码,它成功了。正在回滚。是的,++在undef上有特殊行为特别是为了优化这种情况:undef始终被视为数字,特别是在递增之前被更改为0(这样一个undef值的递增后将返回0而不是undef).
遗憾的是,没有使用+perl
编译Vim,但是由于您的第三个建议与@choroba相同,所以请进行投票s@D_________:perldo
只是基本过滤示例的一个快速替代品,但是这种集成涉及到更多的优秀功能我强烈建议您使用+perl
Vim并查看这些命令的文档
function! Increment()
let g:i += 1
return g:i
endfunction
let g:i = 0 | %substitute/XYZ/\=Increment()/
:%SubstituteExecute /XYZ/ let v:val.n += 1 | return v:val.n
:Renumber /XYZ/