
.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