多くのデータフィールド(> 50)を含む単純化されたCSV(1行に最大1行)がある場合は、各データフィールドの最大文字長をどのように計算してから、すべての数をtxtファイルにエクスポートできますか?ところで、列ヘッダーを含むファイルの最初の行を無視したいと思います。
例えば、入力が与えられると
These,are,the,column_headings_which_may_be_very_long_but_they_don't_count
abcdefghij,abcdefghijk,abcdefghijkl,abc
aardvark,bat,cat,dog
ant,bee,cow,abcdefghijklm
最終結果は次のようになります。ここで、最初の列は元のファイルのデータフィールドを表し、2番目の列はフィールドの最大長を表します。
1 | 10
2 | 11
3 | 12
4 | 13
つまり、列1の最長値は長さ10(abcdefghij
)、列2の最長値は長さ11(abcdefghijk
)です。
私はこのサイトでいくつかの調査を行い、特定のデータフィールドを指定するときに非常に簡単な方法で最大長を計算するいくつかの方法を見つけました。たとえば、ファイル内の2番目のフィールドの最大長を計算するには、cutコマンドとwcコマンドを使用します。
cut -d, -f2 test.csv | wc -L
しかし、どのようにコマンドを取得し、すべてのデータフィールドに繰り返して出力できますか?
答え1
あなたの質問を正しく理解すると、あなたの要件が満たされます。
awk -F, 'NR!=1 { if (max_NF < NF) max_NF = NF;
for (i=1; i<=NF; i++) if (max[i] < length($i)) max[i] = length($i) }
END { for (i=1; i<=max_NF; i++) printf "%-2d | %d\n", i, max[i] }'
答え2
サンプルファイルへのリンクは表示されませんが、awk
コマンドを使用してこれを実行できます。
保持している区切り記号と計算する必要がある正確なフィールドを指定できる場合。
awk '{ FS = "," } ; { if(NR!=1) gsub(/"/, "", $2) ; print NR "|" length($2) } ' test.csv
この出力を目的のファイルにリダイレクトできます。
答え3
使用ミラー( mlr
)各フィールド値の最大長を計算します。入力はCSVに読み込まれ、出力は「xtab」ファイル(ファイルごとに1つのキーと値のペア)として生成されます。
$ mlr --c2x stats1 -a maxlen --fr . file
These_maxlen 10
are_maxlen 11
the_maxlen 12
column_headings_which_may_be_very_long_but_they_don't_count_maxlen 13
--fr .
この操作の引数は、stats1
名前が正規表現に一致するすべてのフィールド.
(つまり、名前付き各フィールド)の最大長を計算することです。
ご覧のとおり、Millerはフィールド名を保持し、_maxlen
各フィールドにサフィックスを追加しました。
最初の行がヘッダーではなくレコードであるかのようにCSVファイルを読み取るには、その最初の行を削除して同じ最大計算を実行します。
$ mlr --c2x -N filter -x 'NR == 1' then stats1 -a maxlen --fr . file
1_maxlen 10
2_maxlen 11
3_maxlen 12
4_maxlen 13
追加操作を使用すると、すべてのフィールド名からサフィックスを削除rename
できます。_maxlen
$ mlr --c2x -N filter -x 'NR == 1' then stats1 -a maxlen --fr . then rename -r '(.*)_maxlen$,\1' file
1 10
2 11
3 12
4 13
答え4
使用幸せ(以前のPerl_6)
~$ raku -ne 'BEGIN my @a;
unless ++$ == 1 {
@a.push: $_.split(",").map: *.chars;
};
END say( ++$ ~ " | " ~ $_ ) for ([Z] @a).map: *.max;' file
または:
~$ raku -ne 'BEGIN my @a;
once next;
@a.push: $_.split(",").map: *.chars;
END say( ++$ ~ " | " ~ $_ ) for ([Z] @a).map: *.max;' file
これはPerlプログラミング言語の1つであるRakuで書かれた答えです。 RakuはUnicodeの高度なサポートを提供し、文字数が正確です。
まず、(awk
同様の)-ne
1行ずつ非自動印刷コマンドラインフラグを使用します。
- 配列は
BEGIN
ブロック単位で宣言されます。 - ヘッダー行(最初の答え)を削除するには、
++$
匿名カウンター()を使用して最初の行をスキップします。または(2番目の答え)、次のものをonce next
使用できます。 split
ブロック/ループ本文内では、各行はコンマで読み取られ、各結果要素は文字数を取得するためmap
に入力されます。これらは配列chars
にプッシュされます。@a
- すべての行を読み取ると、
END
ブロックが実行されます。行と列が交換されるように配列が変換され@a
ます。[Z]
これが発生した場合は、map
各配列位置の要素に入り、匿名カウンタをmax
使用して行番号を指定して.finally出力データを取得できます(文字列接続はチルダで行われます)。++$
~
入力例:
These,are,the,column_headings_which_may_be_very_long_but_they_don't_count
abcdefghij,abcdefghijk,abcdefghijkl,abc
aardvark,bat,cat,dog
ant,bee,cow,abcdefghijklm
出力例:
1 | 10
2 | 11
3 | 12
4 | 13
注:1行あたりの列数を確認してもエラーは発生しません。[Z]
変換は、単純に過度の数の行を共通の行(例では4列)に切り捨てます。 1行あたりの列数に関係なく、Rakuでこれを行うには、以下の最初のリンクを参照してください。
https://unix.stackexchange.com/a/774828/227738
https://docs.raku.org/言語/unicode
https://raku.org