csv列の最初の2行を列ごとにマージする方法は?

csv列の最初の2行を列ごとにマージする方法は?

csvに変換されたExcelファイルがあります。変換後は以下の例のようになります(csvには100を超える列があります。これは縮小版です)。

,Product,"  ",Citty,"   ",Price
,Name," ",Location,"    ",Per Unit
,banana,"   ",CA,"  ",5.7
,apple,"    ",FL,"  ",2.3

1行目と2行目を取得し、コンマの配置に従って「マージ」するスクリプトを作成する必要があります。

,Product Name," ""  ",Citty Location,"  ""  ",Price Per Unit
,banana,"   ",CA,"  ",5.7
,apple,"    ",FL,"  ",2.3

こことStack Overflowで他の質問を見ましたが、答えはファイルの最初の2行の奇妙な列別の状況とは関係がないようです。


無関係な追加操作でcsvから空の列を削除し、タイプミスを修正して次のように見せたいと思います。

Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3

(csvには現在、各実際のデータ列の間に引用符で囲まれたタブがあります。ただし、最初の列は空で、後ろにカンマがあります。)

何度もタイプミスのあるCSVを受け取るので、スクリプトのエラーをプログラムで修正したいと思います。また、列は常に上記の順序で表示されない可能性があるため、スクリプト中に各列名にエラーがないことを動的に確認する必要があります。

答え1

この試み

$ awk -F, 'NR<2{split(gensub(/Citty/,"City","g",$0),a,FS)}NR==2{for(b=2;b<=NF;b+=2){c=c a[b]" "$b","}print gensub(/,$/,"",1,c)}NR>2{print gensub(/(^,|" *",)/,"","g",$0)}' inp
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
$

同じコードを複数行に分割すると、読みやすくなります。

$ awk -F, '
> NR<2{split(gensub(/Citty/,"City","g",$0),a,FS)}
> NR==2{for(b=2;b<=NF;b+=2){c=c a[b]" "$b","}print gensub(/,$/,"",1,c)}
> NR>2{print gensub(/(^,|" *",)/,"","g",$0)}' inp
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
$

最初の行の場合は、行をa内の配列要素に分割します。都市 - >都市スペルエラーを修正しました。

2行目の場合は、2列目から始めて、その列と一緒に1行目の対応する列を印刷します。各列に対してこの操作を2列ずつ繰り返します。末尾のエントリを削除します,

2行目以降は、,前の項目またはすべての項目を"<spaces>",空の文字列に置き換えて結果を印刷します。

GNU Awk 4.0.2でよくテストされました。

オンラインでお試しください!

答え2

Perl、Text::CSV、および MoreUtils の使用:

perl -MText::CSV -MList::MoreUtils=pairwise -lne '
  BEGIN { $p = Text::CSV->new(); } 
  @f = $p->fields() if $p->parse($_);
  @hdr = map { s/Citty/City/ ; $_ } @f if $. == 1;
  @f = pairwise { $a . " " . $b } @hdr, @f if $. == 2;
  print join ",", grep { /\w/ } @f if $. > 1;
' file.csv
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3

grep単語文字が1つも含まれていないフィールドは無視されます。

Perl> = 5.14.0を使用すると、置換を単純化して使用できますmap s/Citty/City/r @fロスレス交換修飾子

答え3

努力する

    awk -F, '
            {gsub (/,*"[    ]*",*/, ",")
             sub (/^,/, "")
             sub (/Citty/, "City")
            }

    NR == 1 {n = split ($0, T)
             next
            }
    NR == 2 {for (;n; n--) $n = T[n] " " $n
            }

    1
    ' OFS=, file
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3

関連情報