複数の子行エントリ(列)を持つCSVをAwkの新しい列に変換するには?

複数の子行エントリ(列)を持つCSVをAwkの新しい列に変換するには?

以下に示す一般形式のCSVファイルがあります。

このCSVには特定の列(desc)に属する複数の行があり、これらの項目を抽出して追加したいと思います。新しい列はname, size, weight, glassそれぞれ呼び出されます。アイテムのサブアイテムを赤で強調表示しました。

元の構造:

ここに画像の説明を入力してください。

期待される構造:

ここに画像の説明を入力してください。


オリジナルCSV:

page,item,id,desc,price
1,2,F1,Alpha,111.11
1,,,380 x 2280 mm (size),
1,,,Weight: 33.0 kg,
1,,,Glass: AAA,
1,,,XXX,
1,3,F2,Beta,222.22
1,,,880 x 2280 mm (size),
1,,,Weight: 68.4 kg,
1,,,Glass: BBB,
1,,,YYY,
1,4,F3,Gamma,333.33
1,,,1980 x 1580 mm (size),
1,,,Weight: 78.2 kg,
1,,,Glass: CCC,
1,,,XXX,
1,,,YYY,
1,,,ZZZ,

期待される生成されたCSV:

page,item,id,name,size,weight,glass,price
1,2,F1,Alpha,380 x 2280,33.0,AAA,111.11
1,3,F2,Beta,880 x 2280,68.4,BBB,222.22
1,4,F3,Gamma,1980 x 1580,78.2,CCC,333.33

どこ名前最初の行を置き換えます説明する


修正する:

特定の条件下では、いくつかのAwkソリューションは上記のように動作しますが、4番目のエントリを追加すると失敗します。徹底的なテストのために上記を追加することを検討してください。

1,7,F4,Delta,111.11
1,,,11 x 22 mm (size),
1,,,Weight: 33.0 kg,
1,,,Glass: DDD,
1,,,Random-1,

したがって、3つの主な事項は次のとおりです。

  • 列のサブ行数は変更descできます。
  • 以降のすべてのサブ行はGlass:...無視する必要があります。
  • があるかもしれませんプロジェクトまったく列内でもdesc無視する必要があります。

Q:次のようにこれらの子行を新しい列に再マップするにはどうすればよいですか?アッ
(またはbashでこれを行うのに適したツールはありますか?)

おそらく関連しているがあまり役に立たない質問:

答え1

awk 'BEGIN{ FS=OFS=","; print "page,item,id,name,size,weight,glass,price" }
    $2!=""{ price=$5; data=$1 FS $2 FS $3 FS $4; desc=""; c=0; next }
          { gsub(/ ?(mm \(size\)|Weight:|kg|Glass:) ?/, "") }
    ++c<=3{ desc=(desc==""?"":desc OFS) $4; next }
    data  { print data, desc, price; data="" }
' infile

説明が含まれます:

awk 'BEGIN{ FS=OFS=","; print "page,item,id,name,size,weight,glass,price" }
     #this block will be executed only once before reading any line, and does: 
            #set FS (Field Separator), OFS (Output Field Separator) to a comma character
            #print the "header" line  ....

    $2!=""{ price=$5; data=$1 FS $2 FS $3 FS $4; desc=""; c=0; next }
    #this blocks will be executed only when column#2 value was not empty, and does:
            #backup column#5 into "price" variable
            #also backup columns#1~4 into "data" variable
            #reset the "desc" variable and also counter variable "c"
            #then read next line and skip processing the rest of the code 

          { gsub(/ ?(mm \(size\)|Weight:|kg|Glass:) ?/, "") }
            #this block runs for every line and replace strings above with empty string

    ++c<=3{ desc=(desc==""?"":desc OFS) $4; next }
    #this block runs at most 3reps and 
           #joining the descriptions in column#4 of every line
           #and read the next line until counter var "c" has value <=3 

     data { print data, desc, price; data="" }
     #if "data" variable has containing any data, then
           #print the data, desc, price and empty "data" variable 
' infile 

関連情報