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内の正規表現はフィールド名の先頭に一致します(各行の先頭に挿入するとこれが行われます)。*
\
^
$
file2
file1
^
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::CSV
CSVを解析するために使用されます。ファイルハンドルはText::CSV.new()
オブジェクトのように定義されます。ファイルハンドル()の最初の行が解析されて保存されるように、この$csvA
オブジェクトに対して機能します。同様に、ファイルハンドル()の最初の行を解析して保存するようにこのオブジェクトを操作します。header
$fhA
column-names
@hdrA
$csvB
header
$fhB
column-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