
100行と数値列を含むCSVテーブルがあります。テーブルのいくつかの数値を含む1列ファイルである別のリストがあります。リストにないCSVのすべての値を削除する方法はありますか?
これをリストファイルとして書き込むことができると思いましたがgrep -f
、削除したい値の一部が保持したい値と同じ行に悩んでいます。
例えば
CSVテーブル:
11,12,13
11,10,12,13
リストファイル:
13
11
出力:
11,,13
11,,,,13
または代替的に
11,13
11,13
答え1
次のawk
手順では、CSV フィールドに先行または末尾の空白がないと仮定します。
awk 'BEGIN {FS=OFS=","}
NR==FNR{valid[$1];next}
{for (i=1;i<=NF;i++) {if (!($i in valid)) {$i=""}}} 1' validvalues.txt input.csv
validvalues.txt
有効な値を含むファイルを最初に処理し、次に実際のCSVファイルを処理します。
BEGIN
セクションでは、入力と出力のフィールド区切り文字がに設定されます,
。- 最初のファイル(ファイルごとの
NR
ラインカウンタと同じグローバルラインFNR
カウンタとして表示されます)を処理するときに許容される値を配列のインデックスとして記録しvalid
、それ以外の場合は次の入力ラインに処理をスキップします。 - 2番目のファイルを処理するときは、すべてのフィールドを繰り返し、フィールドの内容が「配列インデックス」の一部であることを確認してください
valid
。それ以外の場合は、フィールド値を空のフィールドに設定します。 1
これまでのすべての修正を含む、現在の行の見かけ上は汚れて見える印刷です。
重要なのは、($i in valid)
テストが文字列ベースの比較であるため、有効な値ファイルの列エントリまたはCSVファイルのフィールドに先行/末尾のスペースが含まれている場合、比較のために同じスペースが予期しない動作を引き起こす可能性があります。
@glenn jackmanが述べたように手順は次のように単純化できます。
awk 'BEGIN {FS=OFS=","}
NR==FNR{valid[$1]=$1;next}
{for (i=1;i<=NF;i++) {$i=valid[$i]}} 1' validvalues.txt input.csv
ここでは、実際に有効な値を「配列値」としても登録します。無効な値は、項目がないためvalid
自動的valid[$i]
に空の文字列として評価され、有効な値の場合は値自体を返すという考えです。
ただし、「フィールド値自体」を不必要に置き換えてより多くのメモリを必要とするため、パフォーマンスが少し遅くなるため、「有効な値」ファイルが大きい場合は問題になる可能性があります。
答え2
複数文字のRSとRTのGNU awkがある場合:
$ awk -v RS='[,\n]' 'NR==FNR{a[$0]; next} {ORS=RT} $0 in a' list file.csv
11,13
11,13
答え3
不要な値のパイプで区切られたリストを作成できます。
list=$(<list.txt tr '\n' '|')
あなたはします13|11|
。
それからミラー検索と置換
mlr --nidx --fs "," -S put 'for (k in $*) {if($[k]!=~"^('"$list"')$"){$[k] = gsub($[k], $[k], "")}}' input.csv
持つ
11,,13
11,,,13