web-dev-qa-db-ja.com

二重引用符内の区切り記号をawkでエスケープする

入力はcsvファイルなので、awkを使用して、区切り文字として「、」を使用してデータを解析しています。ただし、二重引用符( "...")でエスケープされたデータ内には "、"があります。

filed1,filed2,field3,"field4,FOO,BAR",field5

二重引用符内のコンマ「、」を無視して、awkを使用して出力を正しく解析できるようにするにはどうすればよいですか? Excelでこれを実行できることはわかっていますが、awkではどのように実行するのですか?

27
joomanji

GNU awk 4で簡単です:

_zsh-4.3.12[t]% awk '{ 
 for (i = 0; ++i <= NF;)
   printf "field %d => %s\n", i, $i
 }' FPAT='([^,]+)|("[^"]+")' infile
field 1 => filed1
field 2 => filed2
field 3 => field3
field 4 => "field4,FOO,BAR"
field 5 => field5
_

OP要件に従ってコメントを追加します。

「内容によるフィールドの定義」のGNU awkマニュアル から:

FPATの値は、正規表現を提供する文字列である必要があります。この正規表現は、各フィールドの内容を説明しています。上記のCSVデータの場合、各フィールドは「カンマではないもの」または「二重引用符、二重引用符ではないもの、および終了二重引用符」のいずれかです。正規表現定数として記述した場合、/([^,]+)|("[^"]+")/になります。これを文字列として書き込むには、二重引用符をエスケープする必要があるため、次のようになります。

FPAT = "([^,]+)|(\"[^\"]+\")"

_+_を2回使用すると、これは空のフィールドでは正しく機能しませんが、修正することもできます。

記述されているように、FPATに使用される正規表現では、各フィールドに少なくとも1つの文字が含まれている必要があります。簡単な変更(最初の ‘_+_’を ‘_*_’に変更)では、フィールドを空にすることができます。

FPAT = "([^,]*)|(\"[^\"]+\")"

22

FPATは、引用符で囲まれたフィールド内に改行とコンマがある場合は機能しますが、次のように二重引用符がある場合は機能しません。

field1,"field,2","but this field has ""escaped"" quotes"

私が書いたcsvquoteと呼ばれる単純なラッパープログラムを使用して、awkがデータを簡単に解釈できるようにしてから、問題のある特殊文字を次のように復元できます。

csvquote inputfile.csv | awk -F, '{print $4}' | csvquote -u

コードとドキュメントについては https://github.com/dbro/csvquote を参照してください

11
D Bro

Perlの_Text::CSV_XS_などの本格的なCSVパーサーは、この種の奇妙さを処理するために作成されています。

4番目のフィールドのみを印刷するとします。

Perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){ @f=$csv->fields(); print "\"$f[3]\"" }' file

入力行は配列_@f_に分割されます
Perlは0からインデックス作成を開始するため、フィールド4は_$f[3]_です

私はここで私の答えの中で_Text::CSV_XS_の詳細な説明を提供しました: gawkを使用してcsvファイルを解析

1
Chris Koknat