awkでcsv列を記録し、空のフィールドを考慮してください。

awkでcsv列を記録し、空のフィールドを考慮してください。

複数の列を含むcsvファイルがあるとします。NF一定ではありません。現在4より大きい列を小文字に置き換えるには、次のようにします。

#!/usr/bin/awk
#call with `awk -f lowercase.awk in.csv > out.csv`
BEGIN {
    OFS=",";
    FPAT="([^,]+)|(\"[^\"]+\")";
}
{
    for (i=1; i<=NF; i++){
        if(i>4 && $i){
            $i = tolower($i);
        }
    }
    print $0;
}

ただし、これはcsvファイル内の隣接するフィールド区切り文字(繰り返しカンマで表される空の列)を考慮しません,,,,。これをどのように考慮しますか?私は好きではない解決策はここにあります一般化がうまくいかないためです(条件確認が多いため、実際のアプリケーションはNF40より大きく70未満です)。

ユニットテスト:

入力.csv

apple,orange,banana,cherry,MELON,"Fruit salad",grape
"Lots of vegtables",CUCUMBER,carrot,potato,RADISH,BeetrOOT
Bread,BAGEL,,,,Croissant

出力.csv

apple,orange,banana,cherry,melon,"fruit salad",grape
"Lots of vegtables",CUCUMBER,carrot,potato,radish,beetroot
Bread,BAGEL,,,,croissant

答え1

完了しやすいsed

sed 's/\(\([^,]*,\)\{4\}\)\(.*\)/\1\L\3/' file.csv

エスケープ文字が気に入らない場合は、スクリプトを変更できます(GNU sedの場合)。

sed -r 's/(([^,]*,){4})(.*)/\1\L\3/' file.csv

コンマ以外の記号(0を含む)の4つのグループを見つけて、変更せずに()\1文字列の残りの部分()内\3のすべての項目を下位バージョンに置き換えます。または
によってcutpaste

paste -d, <(cut -d, -f-4 file.csv) <(cut -d, -f5- file.csv | tr '[[:upper:]]' '[[:lower:]]')

答え2

質問が間違って理解された可能性がありますのでご了承ください。tolowerしかし、4(または40または希望する項目)より大きいすべてのフィールドを簡単に処理できる必要があるようです。たとえば、

BEGIN {
    OFS = ","
   }
{
    for (i = 4 ; i <= NF ; i++) {
        $i = tolower($i)
        }
    $1 = $1
    print
}

結局、tolower(*some empty field*)それは完全に空でした。これがうまくいかない理由はありますか?

編集:私の結果:

apple,orange,banana,cherry,melon,"fruit salad",grape
"Lots of vegtables",CUCUMBER,carrot,potato,radish,beetroot
Bread,BAGEL,,,,croissant

関連情報