我需要将ID属性添加到JSON文件中的对象列表中。我发现this有用的内联Perl脚本可以用随机整数替换每个匹配项。
:%! 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
答案 0 :(得分:4)
如果您在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'
答案 1 :(得分:3)
-p
已经逐行处理输入,因此-n
是多余的。
perl -pe 's/XYZ/$i++/ge'
$i++
在数字上下文中返回$i
的值并将其加1。
答案 2 :(得分:3)
使用Perl的built in JSON parser(在5.14及更高版本中),您无需处理可能会出现在其他地方的字符串(无论是否应使用引号和数字,或其他复杂情况),您只需修改JSON作为数据结构(可能需要更改代码以修改完整JSON结构的正确部分):
perl -0777 -MJSON::PP -E'my $data = decode_json readline; $_->{id} = ++$i foreach @$data; print encode_json $data'
最好使用JSON::MaybeXS,因为它将默认安装并使用更快的解析器。
-0777
开关是convention,单线可导致readline或<>
运算符(也由-p开关使用)一次返回整个输入。 / p>
答案 3 :(得分:1)
对于那些寻求纯Vim解决方案的人,这是一个比@sidyll的答案更规范和通用的解决方案,它不需要:perldo
或:global
,并且也可以在行(将g
标志添加到:substitute
):
在Vim中,您可以使用:help sub-replace-expression
将文本替换为任意表达式。不幸的是,递增变量是Vim中的 statement ,而不是表达式。要么必须采取一些技巧,例如使用List的长度作为计数器(add()
可以在表达式中使用):
:let c = [] | %substitute/XYZ/\=len(add(c, 0))/
或者您必须定义一个单独的函数(一次):
function! Increment()
let g:i += 1
return g:i
endfunction
let g:i = 0 | %substitute/XYZ/\=Increment()/
表达式语法有点奇怪(但是,如果您对Perl感兴趣的话,您会变得更糟:-)。同样,计数器(和函数)的显式单独初始化也很麻烦。我的PatternsOnText plugin对内置的:substitute
命令进行了改进,具有多种变体。其中:SubstituteExecute
受益于预定义的上下文对象:
:%SubstituteExecute /XYZ/ let v:val.n += 1 | return v:val.n
重新编号是一项很常见的任务,以至于插件甚至对此都有一个特殊的命令:
:Renumber /XYZ/
xmlstarlet
,对于JSON使用jq
,而不是grep
和sed
)。