2つの異なるcsvファイルから同じ名前の列を抽出する

2つの異なるcsvファイルから同じ名前の列を抽出する

2つの異なるcsvファイルがあります。 1つは拡張列名を含み、もう1つは同じ列名へのショートカットを含みます。

たとえば、

csvファイル1は次のとおりです。

gender,aciclovir drug,aclidinium bromide abc,acenocoumarol drdd
male,2008,2009,2009

csvファイル2は次のとおりです。

gender,aciclovir,aclidinium bromide,ajmaline
male,2008,2009,2010

それでは、ファイル2の列と共通の単語を持つファイル1の列を抽出しようとしています。

私の例に必要な出力を入れるには:

gender,aciclovir drug,aclidinium bromide abc
male,2008,2009

答え1

2つのファイルのヘッダーが特別なCSV参照を持たないカンマ区切りのフィールド名の簡単なリストであると仮定すると、次のコマンドを使用してファイルの他の行からフィールド名を抽出できます。

head -n 1 file | tr , '\n'

またはsed

sed -e 'y/,/\n/' -e q file

また、すべてのフィールド名に正規表現の特殊文字(、、、、、(.フィールド名の先頭)および(フィールド名の終わり))が含まれていないと仮定すると[、それを使用してセットを作成できます。 Will内の正規表現はフィールド名の先頭に一致します(各行の先頭に挿入するとこれが行われます)。*\^$file2file1^

head -n 1 file2 | tr , '\n' | sed 's/^/^/'

またはsed

sed -e 'y/,/\n/' -e q file2 | sed 's/^/^/'

それともsed電話で

sed -e 'y/,/\n/' -e 's/^/^/' -e 's/\n/&^/g' -e q file2

またはGNUを使用してsed

sed -e 's/^/^/' -e 's/,/\n^/g' -e q file2

フィールド名リストにこれらの式を適用して、file1このファイルから抽出する必要があるフィールド名を取得できます。

grep -f <( head -n 1 file2 | tr , '\n' | sed 's/^/^/' ) <( head -n 1 file1 | tr , '\n' )

質問に表示されるデータを考慮すると、結果は次のリストになります。

gender
aciclovir drug
aclidinium bromide abc

file2のフィールド名がのフィールド名を2つ以上一致する場合は、このリストに重複した項目を含めることができますfile1

その後、これらのフィールド名のカンマ区切りリストを作成し、それをcutサブコマンドの引数として使用できます。ミラー最後に必要なフィールドを抽出しますfile1

mlr --csv cut -f "$( grep -f <( head -n 1 file2 | tr , '\n' | sed 's/^/^/' ) <( head -n 1 file1 | tr , '\n' ) | tr '\n' , )" file1

これは私たちに与えるでしょう

gender,aciclovir drug,aclidinium bromide abc
male,2008,2009

答え2

使用幸せ(以前のPerl_6)

raku -MText::CSV -e '  \

  #read headers of each csv, match column names on first word;
      my $csvA = Text::CSV.new; my $csvB = Text::CSV.new; 
      my $fhA = "csv1.csv".IO.open;  my $fhB = "csv2.csv".IO.open; 
      my @hdrA = $csvA.header($fhA).column-names;  my @hdrB = $csvB.header($fhB).column-names; 
      my %fld = @hdrA.map(*.words[0]) (&) @hdrB.map(*.words[0]);  
      close $fhA; close $fhB;

  #read full csv file into @whole array;
      my $fhA_redux = "csv1.csv".IO.open;
      my @whole; my $csv = Text::CSV.new;
      while $csv.getline($fhA_redux) -> $row {
      @whole.push: $row;
      }; close $fhA_redux;

  #output array that has been @whole>>.[index] filtered for desired columns;
     .join(",").put for @whole>>.[@hdrA.map(*.words[0]).grep(/@(%fld.keys)/, :k)];'

RakuはPerlプログラミング言語系列の言語です。 Unicodeと強力な正規表現の実装に対する高度なサポートを提供します。

上記の外部モジュールはText::CSVCSVを解析するために使用されます。ファイルハンドルはText::CSV.new()オブジェクトのように定義されます。ファイルハンドル()の最初の行が解析されて保存されるように、この$csvAオブジェクトに対して機能します。同様に、ファイルハンドル()の最初の行を解析して保存するようにこのオブジェクトを操作します。header$fhAcolumn-names@hdrA$csvBheader$fhBcolumn-names@hdrB

「交差点」を取得するために、@各署名ヘッダー配列はASCII "set-intersection"演算子を使用して他の配列と比較されます(&)。ここでUnicodeシンボルを好む場合はこれを使用できます。交差点は%fldハッシュとして保存されます。

比較(交差)行で各配列要素を分割し、words正確[0]な一致を取得する代わりに、各列の最初の単語が一致するかどうかをテストして一致基準を変更できます。結果は一致する3つの列です。

入力例:

#csv1.csv
gender,aciclovir drug,aclidinium bromide abc,acenocoumarol drdd
male,2008,2009,2009

#csv2.csv
gender,aciclovir,aclidinium bromide,ajmaline
male,2008,2009,2010

出力例(引用符なし):

gender,aciclovir drug,aclidinium bromide abc
male,2008,2009

出力例(二重引用符、>>.raku上記のコードの最後の行の最後に追加されます):

"gender","aciclovir drug","aclidinium bromide abc"
"male","2008","2009"

出力が必要な場合は、csv次のマークダウン文書がこれを示します。

# and write CSV file, filtered as above
my $fh_out = open "new.csv", :w;
$csv.say($fh_out, $_) for @whole>>.[@hdrA.map(*.words[0]).grep(/@(%fld.keys)/, :k)];
$fh_out.close;

https://github.com/Tux/CSV/blob/master/doc/Text-CSV.md
https://docs.raku.org
https://raku.org

関連情報