【问题标题】:Match value in two files and replace values in selected columns匹配两个文件中的值并替换选定列中的值
【发布时间】:2019-02-21 09:04:32
【问题描述】:

目的是检查 file1 中第 3 列和第 4 列的值是否与 file2 中的第 1 列匹配。 如果任何值匹配,则使用 file1 第 5 列和第 6 列的信息替换 file2 中第 2 列和第 3 列的值

另外,我需要将 file1 中的第 7 列和第 8 列的值添加到第 1 列和第 2 列中的 file2 中,用于匹配行,字符 R 用于替换行,O 用于未替换行,

文件1

2,100,31431,37131,999991.70,0000000.30,11111,22222,3
3,100,31431,37471,111113.20,1111111.30,22222,33333,4

文件2

3143137113 318512.50 2334387.50 100
3143137131 318737.50 2334387.50 100
3143137201 319612.50 2334387.50 100
3143137471 322987.50 2334387.50 100
3143137491 323237.50 2334387.50 100

期望的输出:

31431,37113,318512.50,2334387.50,100,O
11111,22222,999991.70,0000000.30,100,R
31431,37201,319612.50,2334387.50,100,O
22222,33333,111113.20,1111111.30,100,R
31431,37491,323237.50,2334387.50,100,O

我试过这两个:

1)

awk '
BEGIN{
  OFS=","
}
FNR==NR{
  a[$3 $4]=$3 OFS $4
  b[$3 $4]=$5
  c[$3 $4]=$6
  d[$3 $4]=$7 OFS $8
  next
}
($1 in
 a){
  $4=d[$1]
  $3=c[$1]
  $2=b[$1]
  $1=a[$1]
  print
  next
}
{
  $1=$1
  sub(/^...../,"&,",$1)
  print
}
' FS=","  file1 FS=" "  file2

输出

31431,37113,318512.50,2334387.50,100
31431,37131,999991.70,0000000.30,11111,22222
31431,37201,319612.50,2334387.50,100
31431,37471,111113.20,1111111.30,22222,33333
31431,37491,323237.50,2334387.50,100

2)

awk -F, 'NR==FNR{a[$3 $4]=substr($0,length($3 FS)+1);next} $1 in a{print a[$1],$NF;next} {$1=substr($1,1,5) OFS substr($1,6,5);} 1' OFS=, file1 FS=' ' file2

输出

31431,37113,318512.50,2334387.50,100
31431,37131,999991.70,0000000.30,11111,22222,3,100
31431,37201,319612.50,2334387.50,100
31431,37471,111113.20,1111111.30,22222,33333,4,100
31431,37491,323237.50,2334387.50,100

两者都有效,但不完全。

提前致谢

【问题讨论】:

  • Perl 解决方案适合您吗?
  • @OXXO,请不要频繁更改您的要求,这是我不得不更改代码的第三次或第四次(在您的问题更改后)。它会让人们认为我们的代码不起作用,甚至可能会感到困惑。只需提供 3 样东西。第一个-您的输入样本,第二个-您的预期输出样本和第三个-您尝试过的(您已经给出的)。要求您不要频繁更改问题。

标签: awk


【解决方案1】:

请您尝试关注一下。

awk '
FNR==NR{
  a[$3 $4]=$7 $8
  b[$3 $4]=$5
  c[$3 $4]=$6
  next
}
($1 in a){
  $2=b[$1]
  $3=c[$1]
  $1=a[$1]
  found=1
}
{
  $0=found==1?$0",R":$0",O"
  sub(/^...../,"&,")
  $1=$1
  found=""
}
1
' FS="," file1 FS=" " OFS="," file2

输出如下。

31431,37113,318512.50,2334387.50,100,O
11111,22222,999991.70,0000000.30,100,R
31431,37201,319612.50,2334387.50,100,O
22222,33333,111113.20,1111111.30,100,R
31431,37491,323237.50,2334387.50,100,O

【讨论】:

  • Ravinder,代码非常感谢,对不起,我修改了一些所需的输出,请您更新代码,,,
  • @OXXO,请不要频繁更改您的要求,这是我第三次或第四次不得不更改我的代码。它会让人们认为我的代码没有产生正确的输出,所以请不要在发布后更改您的问题。请检查一下,现在让我知道吗?
  • Ravinder.. 非常抱歉更改。非常感谢您的帮助 。我会听从你的建议
  • @OXXO,你不必抱歉,伙计,放轻松,我们都在这里互相学习和指导。但是,是的,保持问题不变,要非常诚实,否则它可能会让周围的人感到困惑。在这个很棒的网站上继续学习和分享。
  • Ravinder..tks 很多 .. 会听从您的建议。再次感谢
【解决方案2】:

Perl 版本:

#!/usr/bin/perl
use warnings;
use strict;
use autodie;
use feature qw/say/;

my ($file1, $file2) = @ARGV;
my %rows;

open my $f1, '<', $file1;
while (<$f1>) {
  chomp;
  my @F = split /,/;
  $rows{"$F[2]$F[3]"} = \@F;
}

open my $f2, '<', $file2;
$, = ','; # Like awk OFS
while (<$f2>) {
  chomp;
  my @F = split;
  if (exists $rows{$F[0]}) {
    my $left = $rows{$F[0]};
    say @{$left}[2..5], $F[3], @{$left}[6,7]; 
  } else {
    my ($col1, $col2) = $F[0] =~ m/^(.{5})(.{5})$/;
    say $col1, $col2, @F[1..3];
  }
}

例子:

$ ./example.pl file1.csv file2.txt
31431,37113,318512.50,2334387.50,100
31431,37131,999991.70,0000000.30,100,11111,22222
31431,37201,319612.50,2334387.50,100
31431,37471,111113.20,1111111.30,100,22222,33333
31431,37491,323237.50,2334387.50,100

【讨论】:

  • Shawn,代码非常感谢,对不起,我修改了一些所需的输出,您能更新代码吗,,,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 2018-05-14
  • 2017-07-19
相关资源
最近更新 更多