Regex 用组替换perl正则表达式

Regex 用组替换perl正则表达式,regex,linux,perl,ksh,Regex,Linux,Perl,Ksh,我有以下json输入 ... "somefield":"somevalue", "time":"timevalue", "anotherfield":"value" ... 在我的ksh脚本中,我希望用我的值替换timevalue。因此,我使用组创建了这个正则表达式,但效果很好 data=`cat somefile.json` echo $data | perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | another-scrip

我有以下json输入

... "somefield":"somevalue", "time":"timevalue", "anotherfield":"value" ...
在我的ksh脚本中,我希望用我的值替换timevalue。因此,我使用组创建了这个正则表达式,但效果很好

data=`cat somefile.json`
echo $data | perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | another-script.sh

... "somefield":"somevalue", "time":"%TIME%", "anotherfield":"value" ...
然而。。。我不能使用数字作为替换,因为perl使用数字来定义组。。所以这个显然不起作用

perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\120:00:00\2|g"
我可以通过两步替换来克服这个问题

perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | perl -pe "s|%TIME%|20:00:00|"

... "somefield":"somevalue", "time":"20:00:00", "anotherfield":"value" ...
但我相信有一种更好、更优雅的方法可以做到这一点,虽然你可以用正则表达式来做,但用正则表达式会容易得多

如果您特别希望使用Perl,那么核心Perl发行版自2011年起就包含了一个JSON解析器,因此您可以执行以下操作:

perl -MJSON::PP=decode_json,encode_json -0 -E '$j = decode_json(<>); $j->{time} = "20:00:00"; say encode_json($j)' somefile.json
perl-MJSON::PP=decode_json,encode_json-0-E'$j=decode_json()$j->{time}=“20:00:00”;说encode_json($j)'somefile.json

Perl不使用
\1
进行替换。如果您启用了警告(例如使用
perl-w
),perl会告诉您这是
$1
。可以通过添加
{
}
来消除周围数字的歧义:

perl -pe 's|(.*time"\s*:\s*").*?(".*)|${1}20:00:00$2|g'
(我还删除了正则表达式中所有多余的反斜杠。)

另一方面,如果您只是将其自身替换,那么匹配
*
有什么意义?就不能这样吗

perl -pe 's|(time"\s*:\s*").*?(")|${1}20:00:00$2|g'
?

我不太喜欢
*
*?
。如果您试图匹配带引号字符串的内部,最好是具体的:

perl -pe 's|(time"\s*:\s*")[^"]*(")|${1}20:00:00$2|g'
我们没有尝试验证输入字符串,因此现在也没有理由匹配最终的
(并自行替换):

如果您的perl不是古老的(5.10+),则可以使用
\K
来“保留”字符串的前导部分,即不将其包含在匹配中:

perl -pe 's|time"\s*:\s*"\K[^"]*|20:00:00|g'

现在只有
[^”]*
部分将被替换,这样我们就不必进行任何捕获。

更好、更优雅的方法是使用JSON解析器……它应该是
-0777
,而不是
-0
(假设您想要完整地输入)
-0
将输入行终止符设置为
“\0”
,而不是
undef
。另外,
perl-MJSON::PP-p0777-e'$\uxon=encode\ujson{%{decode\ujson$},time=>“20:00:00”
以实现紧凑性。谢谢,我想我的版本不支持“无法在@INC中找到/json.pm”。我没有更新或安装任何内容的权限,因此无法在基于RedHat的发行版上使用jqAre you?他们中的一些人以恼人的方式拆分标准Perl包。通常会有一个
perl full
或类似名称的包,它为您提供了一切
JSON::PP
自Perl 5.14.IIRC以来一直是标准的,它是旧版RedHat上的
Perl核心!,我先尝试了$1,但错过了转义,然后改为使用\1(现在我知道这是错误的)。如果不逃跑,对我来说是行不通的。perl-w-pe“s |”(.*time\“\s*:\s*”).*?(\“*)\${1}20:00:00\${2}g.您上一个使用\K的解决方案很好,我打算使用这个。非常感谢!@Nir整个问题是您在代码中使用了双引号。如果有疑问,请始终在shell中使用单引号(除非您想插入变量)。
perl -pe 's|(time"\s*:\s*")[^"]*|${1}20:00:00|g'
perl -pe 's|time"\s*:\s*"\K[^"]*|20:00:00|g'