perl正则表达式替换组

Nir*_*Nir 1 regex linux perl ksh

我有以下json输入

... "somefield":"somevalue", "time":"timevalue", "anotherfield":"value" ...
Run Code Online (Sandbox Code Playgroud)

在我的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" ...
Run Code Online (Sandbox Code Playgroud)

但是...我不能使用数字作为替换,因为perl使用数字来定义组..所以这个显然不起作用

perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\120:00:00\2|g"
Run Code Online (Sandbox Code Playgroud)

我可以通过两步替换来克服这个问题

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" ...
Run Code Online (Sandbox Code Playgroud)

但我相信有一种更好,更优雅的方式

Gra*_*ean 7

虽然你可以用正则表达式做到这一点,但使用正确的工具会更容易

jq '.time="20:00:00"' somefile.json 
Run Code Online (Sandbox Code Playgroud)

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

perl -MJSON::PP=decode_json,encode_json -0 -E '$j = decode_json(<>); $j->{time} = "20:00:00"; say encode_json($j)' somefile.json
Run Code Online (Sandbox Code Playgroud)


mel*_*ene 6

Perl不\1用于替代。如果您启用了警告(例如使用perl -w),则perl会告诉您它是$1。通过添加可以将其与周围的数字区分开{ }

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

(我还从正则表达式中删除了所有多余的反斜杠。)

另一方面,.*如果您要自己替换它,匹配的意义何在?不能只是

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

我不是.*or的忠实粉丝.*?。如果您尝试匹配带引号的字符串的内部,则最好进行具体说明:

perl -pe 's|(time"\s*:\s*")[^"]*(")|${1}20:00:00$2|g'
Run Code Online (Sandbox Code Playgroud)

我们并没有尝试验证输入字符串,因此,现在实际上也没有理由匹配该最终字符串"(并自行替换它):

perl -pe 's|(time"\s*:\s*")[^"]*|${1}20:00:00|g'
Run Code Online (Sandbox Code Playgroud)

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

perl -pe 's|time"\s*:\s*"\K[^"]*|20:00:00|g'
Run Code Online (Sandbox Code Playgroud)

现在只有[^"]*零件将被替换,从而使我们不必进行任何捕捉。

  • @Nir整个问题是您在代码周围使用双引号。如有疑问,请始终在外壳程序中使用单引号(除非您要对变量进行插值)。 (2认同)