簡體   English   中英

列中的模式匹配

[英]Pattern Matching in Columns

文件1

A11;F1;BMW
A23;F2;BMW
B12;F3;BMW
H11;F4;JBW

文件2

P01;A1;0;0--00  ;123;456;150
P01;A11;0;0--00  ;123;444;208
P01;B12;0;0--00  ;123;111;36
P01;V11;0;0--00  ;123;787;33.9

輸出量

-;-;-;P01;A1;0;0--00  ;123;456;150
A11;F1;BMW;P01;A11;0;0--00  ;123;444;208
B12;F3;BMW;P01;B12;0;0--00  ;123;111;36
-;-;-;P01;V11;0;0--00  ;123;787;33.9

我試過了

awk 'FNR==NR {a[$2] = $0; next }{ if($1 in a) {p=$1;$1="";print a[p],$0}}' File1 File2 

但沒有工作。

基本上,我想從FILE 1獲取詳細信息並與FILE2(主列表)進行比較。

范例:

FILE2中的A1在FILE1中不可用,因此在輸出文件中,第三個字段的第一個字段為“-”,其余部分為FILE2。 現在,我們有了A11,並在FILE1中獲得了詳細信息。 因此,我們從文件1和文件2中寫入了A11的詳細信息

我個人會在Perl中執行此操作,但是由於每個人及其母親都在為您提供Perl解決方案,因此可以采用以下替代方法:

假設每個文件中的記錄具有一致的字段數,並且每個文件中的記錄均按字典順序按“ join”字段排序,則可以使用join

join -1 1 -2 2 -t ';' -e - -o '1.1 1.2 1.3 2.1 2.2 2.3 2.4 2.5 2.6 2.7' -a 2 File1 File2

選項說明:

  • -1 1-2 2意味着“加入”字段( A11A23 ,等)是在第一場File1和在第二個字段File2
  • -t ';' 表示字段被分隔;
  • -e -表示應將空字段替換為-
  • -o '1.1 1.2 1.3 2.1 2.2 2.3 2.4 2.5 2.6 2.7'意味着想要每個輸出線到由來自前三個字段的File1 ,隨后從所述第一七個字段File2 (這就是為什么這種方法要求每個文件中的記錄具有一致數量的字段的原因。)
  • -a 2意味着要包括每行File2的輸出,即使有一個從沒有相應的行File1 (否則,它將僅輸出兩個文件中都具有匹配項的行。)

Perl常用的方法:使用哈希記住主列表:

#!/usr/bin/perl
use warnings;
use strict;

my %hash;

open my $MASTER, '<', 'File1' or die $!;
while (<$MASTER>) {
    chomp;
    my @columns = split /;/;
    $hash{$columns[0]} = [@columns[1 .. $#columns]];
}
close $MASTER;

open my $DETAIL, '<', 'File2' or die $!;
while (<$DETAIL>) {
    my @columns = split /;/;
    if (exists $hash{$columns[1]}) {
        print join ';', $columns[1], @{ $hash{$columns[1]} }, q();
    } else {
        print '-;-;-;';
    }
    print;
}
close $DETAIL;

使用Perl:

use warnings;
use strict;
my %file1;
open (my $f1, "<", "file1") or die();
while (<$f1>) {
  chomp;
  my @v = (split(/;/))[0];
  $file1{$v[0]} = $_; 
}
close ($f1);
open (my $f2, "<", "file2") or die();
while (<$f2>) {
  chomp;
  my $v = (split(/;/))[1];
  if (defined $file1{$v}) {
    print "$file1{$v};$_\n";
  } else {
    print "-;-;-;$_\n";
  }
}
close ($f2);

在單行程序中,這很不方便,因為它涉及讀取兩個輸入文件,但是問題並不難

該程序從file1讀取所有行,並使用第一個字段作為鍵將行存儲在哈希中

然后,讀取來自file2所有行,並將第二個字段用作訪問哈希的鍵。 //定義或運算符用於打印元素的值(如果存在)或默認字符串(如果不存在)

最后,打印出file2的當前行

use strict;
use warnings;

my %data;

open my $fh, '<', 'file1' or die $!;
while (<$fh>) {
  chomp;
  my $key = (split /;/)[0];
  $data{$key} = $_;
}

open $fh, '<', 'file2' or die $!;
while (<$fh>) {
  my $key = (split /;/)[1];
  print $data{$key} // '-;-;-;', $_;
}

輸出

-;-;-;P01;A1;0;0--00  ;123;456;150
A11;F1;BMWP01;A11;0;0--00  ;123;444;208
B12;F3;BMWP01;B12;0;0--00  ;123;111;36
-;-;-;P01;V11;0;0--00  ;123;787;33.9

perl解決方案可能包括非常好的模塊Text :: CSV 如果是這樣,您可以將值提取到哈希中,然后再使用該哈希進行查找。 查找值時,您將插入空白值-;-;-; 查找哈希中任何未定義的值。

use strict;
use warnings;
use Text::CSV;

my $lookup = "file1.csv";   # whatever file is used to look up fields 0-2
my $master = "file2.csv";   # the file controlling the printing

my $csv = Text::CSV->new({
        sep_char    => ";", 
        eol         => $/,  # to add newline to $csv->print()
        quote_space => 0,   # to avoid adding quotes 
    });

my %lookup;

open my $fh, "<", $lookup or die $!;

while (my $row = $csv->getline($fh)) {
    $lookup{$row->[0]} = $row;    # add entire row to specific key
}
open $fh, "<", $master or die $!; # new $fh needs no close

while (my $row = $csv->getline($fh)) {
    my $extra = $lookup{$row->[1]} // [ qw(- - -) ]; # blank row if undef
    unshift @$row, @$extra;       # add the new values
    $csv->print(*STDOUT, $row);   # then print them
}

輸出:

-;-;-;P01;A1;0;0--00  ;123;456;150
A11;F1;BMW;P01;A11;0;0--00  ;123;444;208
B12;F3;BMW;P01;B12;0;0--00  ;123;111;36
-;-;-;P01;V11;0;0--00  ;123;787;33.9

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM