【问题标题】:How to use backreference multiple times?如何多次使用反向引用?
【发布时间】:2017-03-27 20:12:37
【问题描述】:

dump.data 如下:

x"xxx":111,"xxxx":2222,xxxx"id":123,xxxxxx"value":321,xxxxxx"id":234,xxxxxx"value":432,xx
x"xxx":yyy,"xxxx":zzz,xxxx"id":223,xxxxxx"value":221,xxxxxx"id":224,xxxxxx"value":232,xxxx....

我只想过滤 idvalue 信息。例如在任何过程给我这个之后:

"id":123,"value":321,"id":234,"value":432
"id":223,"value":221,"id":224,"value":232

我想到的是使用反向引用,即 sed:

sed 's|.*\("id":[0-9]*\).*\("value":[0-9]*\).*|\1,\2|' dump.data

这给了我这个:

"id":234,"value":432
"id":224,"value":232

但是我怎样才能获得所有 id 和 value 信息?

【问题讨论】:

  • 这可能有助于第一步:grep -o '"[^,]*' dump.data
  • 感谢您的宝贵时间,问题已更新。 @赛勒斯
  • 这可能有助于作为第二步:grep -oE '"(id|value)[^,]*' dump.data
  • 明白你的意思!谢谢! @赛勒斯
  • 并附加| tr '\n' ','(用,替换每个换行符),最后一步找到删除尾随,的方法。

标签: perl shell awk sed


【解决方案1】:

其他解决方案的简化版本

$ perl -lne 'print join ",", /"[^"]+":\d+/g' dump.data 
"id":123,"value":321,"id":234,"value":432
"id":223,"value":221,"id":224,"value":232
  • "[^"]+":\d+ 要提取的模式
  • join "," 使用, 作为分隔符来组合提取的模式


仅捕获 idvalue

$ perl -lne 'print join ",", /"(?:id|value)":\d+/g' dump.data
"id":123,"value":321,"id":234,"value":432
"id":223,"value":221,"id":224,"value":232
  • (?:id|value) 仅限于 idvalue,但在非捕获组中,以便仅将整个提取的文本传递给 join

【讨论】:

  • 我试过perl -lne 'print join ",", /"(id|value)":\d+/g' dump.data,它只产生id,value,id,value..
  • perl -lne 'print join ",", /("(id|value)":\d+)/g' dump.data 有效!我假设 print 适用于\1 capture?
  • 您确定/("(id|value)":\d+)/g 有效吗?由于(id|value),它将不必要地添加额外的idvalue 到输出中
【解决方案2】:

使用 GNU awk 进行 FPAT:

awk -v FPAT='"(id|value)":[0-9]+' '{for (i=1;i<=NF;i++) printf "%s%s", $i, (i<NF?",":ORS)}' file
"id":123,"value":321,"id":234,"value":432
"id":223,"value":221,"id":224,"value":232

【讨论】:

  • 好一个!在你之前我不知道 FPAT .. Thx
【解决方案3】:

尝试以下 awk 解决方案 -

#awk 'BEGIN{FS="x+|y+|z+"} {print  $7,$8,$9,substr($10,1,length($10)-1)}' OFS="" kk.txt
"id":123,"value":321,"id":234,"value":432
"id":223,"value":221,"id":224,"value":232

解释:

  1. "x+|y+|z+" : BEGIN 块中的多个字段分隔符。
  2. substr($10,1,length($10)-1) :删除列的最后一个字符 在我们的例子中是“,”。

【讨论】:

    【解决方案4】:

    使用while 循环一次捕获一对,每次都打印

    perl -lne 'print "$1:$2" while /("[^"]+"):(\w+),/g' data.txt
    

    然后您可以通过在行尾添加&gt; output.txt 将其重定向到文件。

    每行输出一对。将每一行的对保持在一行上

    perl -nE 'chomp; print "$1:$2," while /("[^"]+"):(\w+),/g; say ""' data.txt
    

    这会在最后一行之后留下一个额外的逗号。为了避免这种情况

    perl -lne 'push @m, "$1:$2" while /("[^"]+"):(\w+),/g; print join ",", @m; @m = ()' data.txt
    

    这会形成每对的"$1:$2" 并将其添加到数组中。处理完该行后,它会打印出由, 连接的行。然后数组被@m = () 清空以用于下一行。

    如果周围可能有多余的空格,请添加\s*,例如\s*:\s*

    【讨论】:

    • 感谢您的时间,但这会产生与我上面提到的 sed 相同的结果。
    • @hedleyyan 已修复
    • 如果 dump.data 有多行,我希望结果保留在相对行中怎么办?问更新了。谢谢! @zdim
    • @hedleyyan 添加了另一种情况,有点复杂,但避免了前一个在最后一行之后产生的额外逗号
    • @hedleyyan 很高兴这样做 :) 说真的,这是我的观点,而不是将其缩减为一种解决方案——这些可以在普通程序中使用,并且具有灵活性(可以使用不同的分隔符,调整正则表达式以获得额外的模式等)。
    【解决方案5】:

    如下尝试

    perl -ne 'while($_=~m/(?:("id":\d+)|("value":\d+))/g){my $result = $1 // $2; print "$result ";} print "\n";' data.dump
    

    【讨论】:

    • 虽然这段代码 sn-p 可以解决问题,包括解释 really helps 以提高您的帖子质量。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人!请edit您的答案添加解释,并说明适用的限制和假设。
    猜你喜欢
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多