Skip to content

Instantly share code, notes, and snippets.

@ytez
Last active October 15, 2022 02:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ytez/af41ea5f4755b98693f6eaa2b09eb1cf to your computer and use it in GitHub Desktop.
Save ytez/af41ea5f4755b98693f6eaa2b09eb1cf to your computer and use it in GitHub Desktop.
AWK: フィールド内に改行(LF)を含むCSVをパースしてみる (for @callmekohei)
#!/usr/bin/gawk -f
BEGIN{
RS="\r\n"
FPAT="[^,]+|\"[^\"]+\""
OFS= " --> "
}
{
gsub(/\n/, "<LF>", $0);
print $1, $2, $3
}
# $ echo -ne '"a","b\n","c"\r\n"1","2\n","3"\r\n' | ./linebreak_in_fields.awk
# "a" --> "b<LF>" --> "c"
# "1" --> "2<LF>" --> "3"

概要

フィールド内も行セパレータも両方とも LF だともはや AWK の仕事ではないと思うので、 ExcelからエクスポートしたCSV に限定して処理してみようと思う。

CSVの条件

  • 行セパレータは CR+LF
  • フィールド内に LF (セル内で Alt + Enter してできるやつ) を含む
  • フィールド内に LF を含む場合、""で囲まれている

パース方針

  • RS="\r\n" を設定し、フィールド内の LF で行分割されないようにする
  • FPAT="[^,]+|\"[^\"]+\"" を設定し、フィールド内に LF を許容する
  • フィールド内の LF を適当な文字列に置換して表示させてみる

用意したCSVの確認

$ cat linebreak_in_fields.csv
a,"b
",c
1,"2
",3

$ cat linebreak_in_fields.csv | tr "\r\n" "^@"
a,"b@",c^@1,"2@",3^@

条件のとおりになっている。

AWKスクリプト実行

$ ./linebreak_in_fields.awk linebreak_in_fields.csv
a --> "b<LF>" --> c
1 --> "2<LF>" --> 3

うまくいった。

修正

2019-06-04

FPATがおかしかったので直す。

あと、LF はどうやら AWK においては /./ でマッチさせられる模様

$ awk 'BEGIN{print ("\n" ~ /./)}'
1
$ awk 'BEGIN{print ("\r" ~ /./)}'
1
$ awk 'BEGIN{print ("\t" ~ /./)}'
1
$ awk 'BEGIN{print (" "  ~ /./)}'
1

ということは FPAT="[^,]+|\"[^\"]+\"" これでいいはずだ

ちなみにPerlだと m//s オプションを使わないとダメ

$ perl -Wle '{ print (("\n" =~ m/./ ) ? 1 : 0) }'
0
$ perl -Wle '{ print (("\n" =~ m/./s) ? 1 : 0) }'
1

ToDo

  • マルチバイト文字を含む場合
  • エンコードが UTF-8 じゃない場合

とか。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment