Unixファイルには、引用符の中に改行文字が含まれています。

Unixファイルには、引用符の中に改行文字が含まれています。

引用符の中に引用符と改行文字がありますが、単一の列にはない奇妙なCSVファイルがあります。これで、列を「改行」として識別し、改行をいくつかの区切り文字に置き換える必要があります。

3つの列があり、3番目の列には二重引用符と各特殊文字を含むHTMLテキストが含まれています。ただし、二重引用符はのような二重引用符でエスケープされます"<This ""is"" string>"

入力する:

ID、名前、文字

"1","abc","Line 1"
"2","def","Line2
""line2"",line2"
"3","ghi","line3"

出力:

ID, Name, text
"1","abc","Line 1"
"2","def","Line2 ""line2"",line2"
"3","ghi","line3"

答え1

ファイルに実際の問題はありません。改行と二重引用符が含まれています。 CSVパーサーはこれを正しく処理します。エスケープされた二重引用符"(二重引用符フィールドの間)を使用することは、CSVファイルに含まれる二重引用符をエスケープする正しい方法です。

交換埋め込みCSVファイルに@改行文字を含めるには:

$ csvformat -M '@' file.csv | tr '\n@' '@\n'
1,abc,Line 1
2,def,"Line2@""line2"",line2"
3,ghi,line3

これはcsvformat以下で使用されます。csvkitツールキット。これはCSVファイルを再フォーマットできる適切なCSVパーサーです。

上記のコマンドパイプラインは最初にすべての改行を置き換えます。いいえ役割が含まれます@。その後、tr残りの改行文字と@文字を置き換えて、改行文字を含むCSVファイルに仕上げました@

これは、ファイルの元のデータに文字が含まれていないという事実に依存します@

改行文字が元々あった場所の代わりに空白のあるトークンが必要な場合は、上記のトークンを代わりtr '\n@' ' \n'に使用してください。tr

$ csvformat -M '@' file.csv | tr '\n@' ' \n'
1,abc,Line 1
2,def,"Line2 ""line2"",line2"
3,ghi,line3

これにより、元の改行文字を再挿入することが不可能ではない場合でも、非常に困難になります。その他データの空白(たとえば、最初の行の3番目のフィールドの空白)

csvformat不要な二重引用符をすべて削除せずに次のように使用しますか-U 1

$ csvformat -U 1 -M '@' file.csv | tr '\n@' ' \n'
"1","abc","Line 1"
"2","def","Line2 ""line2"",line2"
"3","ghi","line3"

Millerを使用してより簡単な答えを得る(2022年10月):

$ cat file
ID,Name,text
"1","abc","Line 1"
"2","def","Line2
""line2"",line2"
"3","ghi","line3"
$ mlr --csv put '$text = gsub($text,"\n"," ")' file
ID,Name,text
1,abc,Line 1
2,def,"Line2 ""line2"",line2"
3,ghi,line3

その後、CSVファイル(通常のヘッダーと仮定)を読み取り、gsub()フィールドの改行を空白に置き換えます。text

答え2

sedを試してみてください。

sed '
  :A
  2,$ {
    /[^"]\"$/! {
      N
      bA
    }
    s/\n//g
  }
' infile

最後の文字が「の場合、2から最後まですべての行をキャプチャします。
そうでない場合は、改行文字を取得してループを再開します。
ループの末尾から各「\ n」を削除します。

答え3

sed次のような拡張正規表現サポートを活用して、GNUバージョンを使用してこれを実行できます。

コマンドライン:

$ sed -Ee '
   1b
   /^("[^"]*"[^"]*)*$/!{
      N;s/\n/ /;s/^/\n/;D
   }
' input.csv

結果:

ID,Name,Text
"1","abc","Line 1"
"2","def","Line2 ""line2"",line2"
"3","ghi","line3"

説明する:

  • -E拡張正規表現モードをオンにします。
  • 1bヘッダは変更されず、標準出力に送信されます。
  • /^("[^"]*"[^"]*)*$/二重引用符で完全にバランスのとれた行を一致させます。
  • したがって、これを否定すると、不均衡行、IOWが発生し、後続の行で閉じる二重引用符を見つける必要があります。
  • 次の行を読み、パターンスペースに追加してN改行を削除します。
  • パターンスペースがバランスをとるまでこのプロセスを繰り返します。

POSIX sed上記の内容をいくつか変更する必要があります。

$ sed -e '
   1b
   /^\("[^"]*"[^"]*\)*$/b
   N;s/\n/ /;H;s/.*//;x;D
' input.csv

答え4

Raku(以前のPerl_6)の使用

raku -MText::CSV -e 'my $csv=Text::CSV.new;  .perl.put for $csv.getline_all(open($*ARGFILES, :r, :!chomp));' 

入力例:

ID, Name, text
"1","abc","Line 1"
"2","def","Line2
""line2"",line2"
"3","ghi","line3"

出力例:

$["ID", "Name", "text"]
$["1", "abc", "Line 1"]
$["2", "def", "Line2\n\"line2\",line2"]
$["3", "ghi", "line3"]

Rakuプログラミング言語と特殊モジュール(例Text::CSV:)を使用して、引用符と埋め込み改行を処理できます。可視化のために\n呼び出された役割を追加しました.perl(参考用として.raku も問題ありません)。埋め込まれた改行を下線に変更するには、フィールドにマッピングを追加します(下記のコード)。

raku -MText::CSV -e 'my $csv=Text::CSV.new;  .put for $csv.getline_all(open($*ARGFILES, :r, :!chomp)).map(*.subst("\n","_", :g));' 

出力更新(1):

ID Name text
1 abc Line 1
2 def Line2_"line2",line2
3 ghi line3

「大きな」二重引用符が必要かどうかは、OPの元の公開では実際には不明です。.perl上記のコードにコールバックを追加すると、エスケープされた二重引用符(下)が表示されます。これはこれ以上の可能性があります。

出力更新(2):

"ID Name text"
"1 abc Line 1"
"2 def Line2_\"line2\",line2"
"3 ghi line3"

https://modules.raku.org/dist/Text::CSV:cpan:HMBRAND
https://github.com/Tux/CSV
https://raku.org

関連情報