CSVファイルの特定の列から改行を削除する方法は?

CSVファイルの特定の列から改行を削除する方法は?

改行をレコード区切り文字として使用する150を超える列を含むCSVファイルがあります。問題は、列の1つに改行文字が含まれることです。そのためには、これらを削除したいと思います。

入力する:

001|Baker St.
London|3|4|7
002|Penny Lane
Liverpool|88|5|7

出力:

001|Baker St. London|3|4|7
002|Penny Lane Liverpool|88|5|7

答え1

sed現在の行に4文字が含まれていない場合は、|次の行を現在の行にマージできます。

<file sed -e :1 -e 's/|/|/4;t' -e 'N;s/\n/ /;b1'

一部のsed実装では、ファイルを所定の位置にあるか編集することができます(-i元のファイルを拡張子として保存するため)、これを使用して次のことができます。-i ''-i.back.back

sed -i -e :1 -e 's/|/|/4;t' -e 'N;s/\n/ /;b1' ./*.csv

csv現在のディレクトリに隠されていないすべてのファイルを編集します。

コメントと同じ:

<file sed '
   :1
     s/|/|/4; # replace the 4th | with itself. Only useful when combined with
              # the next "t" command which branches off if the previous
              # substitution was successful
     t
     # we only reach this point if "t" above did not branch off, that is
     # if the pattern space does not contain 4 "|"s
     N; # append the next line to the pattern space
     s/\n/ /; # replace the newline with a space

   # and then loop again in case the pattern space still does not contain
   # 4 "|"s:
   b1'

答え2

最初のフィールドの形式によって異なります(各行が数字で始まると仮定)。

awk 'NR == 1{ printf $0; next }
     { printf "%s%s", (/^[0-9]+/? ORS : ""), $0 }
     END{ print "" }' file.csv

出力:

001|Baker St.London|3|4|7
002|Penny LaneLiverpool|88|5|7

答え3

別のGNUawkソリューションは、各レコードに|4回依存します。

awk -v RS='([^|]+\\|){4}[^|]+\n' '{gsub(/\n/," ",RT); print RT}' file

RS4つの区切り文字を含むレコードに設定します(改行を含む)。

RT記録が確立されましたRSgsubレコードから改行を削除します。

答え4

フィールドが2つしかない行から末尾の改行文字を削除する必要があると仮定できる場合は、Perlで次のことを実行できます。

$ perl -F"\|" -lane '$#F==1 ? printf : print' file.csv 
001|Baker St.London|3|4|7
002|Penny LaneLiverpool|88|5|7

重要な免責事項:Stéphane Chazelasのコメントで指摘したように、これは入力に%文字が含まれていないと仮定しています。なぜなら、文字が含まれていると、その文字が書式指定子として扱われるからですprintf。これは、単に誤った出力を印刷することから食べることまで、意図しない結果をもたらす可能性があります。ジムRAM、入力に%02147483600f%02147483600f%02147483600f%02147483600f

説明する

  • -aperl:と同じ動作を作成しawk、与えられた文字から各入力行を分割し-F(ここでa;はperl正規表現でORを意味する|のでエスケープする必要があります)、結果を配列として保存します。\||@F
  • -l:各入力行から末尾の改行を削除し、'n各呼び出しにtを追加しますprint
  • -ne: 入力ファイルを 1 行ずつ読み込み、与えられたスクリプトを-e各行に適用します。
  • $#F==1 ? printf : print'$#F変数は配列の要素数@F、つまりフィールド数です。これは、フィールド数が1の場合(既存の行が削除され、1つが追加されないため、改行なしで現在の行を印刷する)ことを意味しますprintf。フィールド数が正確に1でない場合は、改行が追加されるためです。-lprintfprint-l

同じ内容を次に拡張できます。

$ perl -e 'while($line=<STDIN>){
            chomp $line; 
            @fields=split(/\|/,$line); 
            if(scalar(@fields) == 2){
                print "$line";
            } 
            else{
                print "$line\n"
            }
           }' < file.csv 
001|Baker St.London|3|4|7
002|Penny LaneLiverpool|88|5|7

@Sundeepはコメントでより短いバージョンを提案しました。

perl -F'\|' -ape 'chomp if $#F==1'

関連情報