非分割フィールドの値を保持しながら、CSVファイル内の特定のフィールドを分割して複数の行に分散します。

非分割フィールドの値を保持しながら、CSVファイル内の特定のフィールドを分割して複数の行に分散します。

.csv次のファイルがあります。

IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP$DOLAP,200000000$2048000,400000000$2048000,200000000,400000000,5,5

$シンボルの前の部分は元の行に残り、後ろの部分はファイル内の他のフィールドが で同じ値を保持する直下に新しく作成された行に転送されるように、シンボルを含むすべてのフィールドを分割したいと思います。区切り文字が最初に見つかった行です。行の複数のフィールドに区切り文字が含まれている場合は、すべてのフィールドの「2番目」の部分が新しく作成された同じ行に転送されます。

上記の例では、出力は次のようになります。

IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP,200000000,400000000,200000000,400000000,5,5
NAN,NAN,2,,,0,,0,,,,DOLAP,2048000,2048000,200000000,400000000,5,5

答え1

@Paul_Pedantが言及したポイントは実際にはタイプミスであり、フィールドも分割されるとOLAP$DOLAP仮定します。この場合、次のawk手順(と呼ばれるsplitfields.awk)が機能する可能性があります。

#/usr/bin/awk -f
{
    copy=0;

    for (i=1;i<=NF;i++)
    {
        j=index($i,"$");
        if (j>0)
        {
            fields[i]=substr($i,j+1);
            $i=substr($i,1,j-1);
            copy=1
        }
        else fields[i]=$i;
    }
    print;

    if (copy==1)
    {
        for (i=1;i<NF;i++) printf("%s%s",fields[i],OFS);
        printf("%s%s",fields[NF],ORS)
    }
}

電話してください。

user@host~$ awk -F, -v OFS="," -f splitfields.awk input.csv

スクリプトは各フィールドにシンボルがあることを確認し、さらに使用するために$フィールドを配列にコピーします。見つかったらfields、対応$するフィールド現在のラインが部品に縮小今後配列$の対応する項目がいっぱいにfieldsなると後ろにこれ$

この確認を行った後、(修正可能な)現在の行がとにかく印刷されます。また、フィールドにこのシンボルが含まれている場合は、配列の内容$で構成された新しい行がCSV形式で印刷されます。fields

答え2

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    delete subFlds
    numSubFlds = 0
    for (i=1; i<=NF; i++) {
        n = split($i,parts,/[$]/)
        for (subFldNr=1; subFldNr<=n; subFldNr++) {
            subFlds[i,subFldNr] = parts[subFldNr]
        }
        numSubFlds = (numSubFlds > n ? numSubFlds : n)
    }

    delete prev
    for (subFldNr=1; subFldNr<=numSubFlds; subFldNr++) {
        for (i=1; i<=NF; i++) {
            curr = ( (i,subFldNr) in subFlds ? subFlds[i,subFldNr] : prev[i] )
            printf "%s%s", curr, (i<NF ? OFS : ORS)
            prev[i] = curr
        }
    }
}

$ awk -f tst.awk file
IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP,200000000,400000000,200000000,400000000,5,5
NAN,NAN,2,,,0,,0,,,,DOLAP,2048000,2048000,200000000,400000000,5,5

答え3

awk -F, -v OFS=, '{split("",q);for(i=j=1;i<=NF;i++){if(split($i,a,/\$/)>1){j++;$i=a[1];q[i]=a[2]}}print;if(j>1){for(i in q)$i=q[i];print}}' file

または拡張して、次の操作を行います。

awk -F, -v OFS=, '{
  split("", q)       # clear the q array; delete q is non-standard
  for(i = j = 1; i <= NF; i++){
    if(split($i, a, /\$/) > 1){  # if the field contains a $
       j++                # increase the cnt of fields with a $
       $i = a[1]          # set the field to the part before the $
       q[i] = a[2]        # save the part after the $ in the q array
    }
  }
  print                   # print the line with the parts before $
  if(j > 1){              # if any field had a $
     for(i in q)          # for each field which had a $
       $i = q[i]          # replace it with the part after $  
     print                # re-print the line with the parts after $
  }
}' file

答え4

私が正しく理解した場合、いくつかのフィールドは「デュアル」バリアントフィールドに分かれています$。その行のコピーは2つだけです。ここで、第1行は第1変形を含み、第2行は第2変形を含む。

awk '{v1=$0; gsub(/\$[^,]+/,""); gsub (/,[^,]+\$/,",",v1); print $0; if (v1!=$0) print v1}' file1

IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP,200000000,400000000,200000000,400000000,5,5
NAN,NAN,2,,,0,,0,,,,DOLAP,2048000,2048000,200000000,400000000,5,5

関連情報