分割线并替换缺失的字段

分割线并替换缺失的字段

有谁知道我如何“拆分”下面的行(这只是一个例子):

mercedes|$40000|black|$42000|white|$41000|red
audi|$31000|blue|$10000|white
mercedes|$5000|blue

我期望的输出是:

mercedes|$40000|black
mercedes|$42000|white
mercedes|$41000|red
audi|$31000|blue
audi|$10000|white
mercedes|$5000|blue

谢谢

答案1

一个简单的awk脚本,用于从第二个字段开始的每行输出字段对,并为每个输出对添加该行的第一个字段作为前缀。

$ awk -F '|' 'BEGIN { OFS=FS } { for (i = 2; i+1 <= NF; i += 2) print $1, $i, $(i+1) }' file
mercedes|$40000|black
mercedes|$42000|white
mercedes|$41000|red
audi|$31000|blue
audi|$10000|white
mercedes|$5000|blue

这假设输入符合预期,即最终数据应组织为三列。这意味着输入应严格遵循

title|pair 1a|pair 1b|pair 2a|pair 2b|...|pair Na|pair Nb

答案2

awk -F'[|]' '{ for(i=3; i<NF; i+=2) sub($i, $i ORS $1) }1' infile

请注意,第一个参数sub(regexp, replacement [, target])功能是个正则表达式所以它将把 the$i视为正则表达式

另请参阅更多关于'\' 和 '&' 与 sub()、gsub() 和 gensub() 函数当谈到这些函数的第二个参数时也是如此。


或者,按照以下方式执行,而不会出现上述 sub() 问题:

awk 'BEGIN{ FS=OFS="|" } { for(i=3; i<NF; i+=2) $i= $i ORS $1 }1' infile 

答案3

pythonitertools模块一起重复提供第一个字段以填充前两个字段。

python3 -c 'import sys
import itertools as it
ifile = sys.argv[1]
ofs = fs = "|"
with open(ifile) as f:
  for l in f:
    L = l.rstrip("\n").split(fs)
    for a,b in zip(it.repeat(L.pop(0)),zip(*[iter(L)]*2)):
      print(a,*b,sep=ofs)
' file

perl也可以用于我们打印前导第 2+3 个字段以及第一个字段,然后删除第 2 个和第 3 个字段,从而允许下一个字段取代它们的位置。

perl -F'[|]' -lane '$,="|";
  print $F[0], splice(@F,1,2)
    while @F > 3;
  print @F;
' file

GNU sed启用扩展正则表达式模式-E

  • 标记到第三个字段的末尾,准备从字段 1 到字段 3 进行打印。
  • 复制第三个字段后的第一个字段,为下一轮打印做准备。
sed -Ee '
  s/[|]/\n/3;P
  s/^([^|]+[|]).*\n/&\1/;D
' file

解释:

  • 想象一条像这样的线:
    • 汽车品牌 | p1 | c1 | p2| c2 | ... |上 |中文
  • 我们希望品牌与价格/颜色元组单独在一条线上配对。
  • 将第三个管道分隔符替换为换行符:s/[|]/\n/3
  • 现在可视化模式空间:
    • 汽车品牌 | p1 | c1 \n p2 | c1 \n p2 | c1 \n p2 | 2 | ... |上 |中文
  • sed 命令P(大写 pee)打印到标准输出,直到第一个换行符。
  • 到此阶段的输出为:
    • 汽车品牌 | p1 | c1
  • 第一对价格/颜色的使用就结束了。现在需要做的是将汽车品牌复制到下一个价格/颜色对:
    • s/^([^|]+[|]).*\n/&\1/
    • 括号记住匹配的内容,即:前导数据,包括第一个管道分隔符。我们匹配直到换行。替换部分是与我们记忆中的(汽车品牌|)相匹配的部分(&)。
    • 模式空间现在看起来像 Car_brand | p1 | c1 \n 汽车品牌 | p2| c2 | ... | l pn |中文
  • Delete 命令一直持续到第一个换行符
    • 模式空间现在变成了 Car _brand | p2| c2 | ..| PN |中文
  • 该命令的属性D是,在删除直到第一个换行符并提供剩余内容后,它将 sed 代码重新应用到剩余的模式空间。
  • 简而言之,这相当于一个循环动作。

结果:

mercedes|$40000|black
mercedes|$42000|white
mercedes|$41000|red
audi|$31000|blue
audi|$10000|white
mercedes|$5000|blue

答案4

perl

perl -F"\|" -le '$,="|";
for (my $a=1;$a<@F;$a+=2) 
{print $F[0],$F[$a], $F[$a+1]}' input
  • -F"\|"输入字段分隔符设置为|
  • $,="|";输出字段分隔符设置为|
  • $a<scalar @F;这里scalar @F告诉了字段的总数,$a<scalar @F因为 Perl 中的字段从零开始。

这是答案由 @Kusalananda 但在perl.

相关内容