我有一个如下所示的数据文件:
xyz123 2.000 -0.3974 0.0 hij123
6.0 lmn123
8.7 efg123
13.9 uvw123
28.5 rst123
abc123 10.000 0.1943 0.0 wxy123
10.7 xyz123
19.9 pqr123
20.6 stu123
20.6 klm123
def123 50.000 -0.2595 19.2 jkl123
26.1 stu123
27.1 def123
27.1 ghi123
27.6 abc123
* uvw123 15.000 -0.3635
lmn123 40.000 -0.3695 19.2 jkl123
26.1 stu123
27.1 def123
27.1 ghi123
27.6 abc123
我需要将其转换为:
xyz123,2.000,-0.3974,0.0,hij123
xyz123,2.000,-0.3974,6.0,lmn123
xyz123,2.000,-0.3974,8.7,efg123
xyz123,2.000,-0.3974,13.9,uvw123
xyz123,2.000,-0.3974,28.5,rst123
abc123,10.000,0.1943,0.0,wxy123
abc123,10.000,0.1943,10.7,xyz123
abc123,10.000,0.1943,19.9,pqr123
abc123,10.000,0.1943,20.6,stu123
abc123,10.000,0.1943,20.6,klm123
def123,50.000,-0.2595,19.2,jkl123
def123,50.000,-0.2595,26.1,stu123
def123,50.000,-0.2595,27.1,def123
def123,50.000,-0.2595,27.1,ghi123
def123,50.000,-0.2595,27.6,abc123
* uvw123,15.000,-0.3635,
lmn123,40.000,-0.3695,19.2,jkl123
lmn123,40.000,-0.3695,26.1,stu123
lmn123,40.000,-0.3695,27.1,def123
lmn123,40.000,-0.3695,27.1,ghi123
lmn123,40.000,-0.3695,27.6,abc123
如何使用Python或AWK或sed执行此操作?
更新:所以如果你注意到输入数据中有一行看起来像“uvw123 15.000 -0.3635”,当我使用aix的python代码时,这一行就搞砸了。有没有办法修改代码并正确输出行,例如我展示的行?
答案 0 :(得分:1)
这是一个Python解决方案:
import re
with open('data.txt') as f:
prev = []
for line in f:
tok = [t for t in re.split(r'\s+', line.rstrip()) if t]
if len(tok) < len(prev):
tok = prev[:-len(tok)] + tok
print ','.join(tok)
prev = tok
它会跟踪每列的最新值(在prev
中)并使用它来填充当前行中缺少的列。
答案 1 :(得分:1)
awk 'BEGIN {OFS = ","} NF == 5 {a = $1; b = $2; c = $3; $1 = $1; print; next} {$4 = $1; $5 = $2; $1 = a; $2 = b; $3 = c; print}' inputfile
分成多行:
awk 'BEGIN {
OFS = ","
}
NF == 5 {
a = $1;
b = $2;
c = $3;
$1 = $1;
print;
next
}
{
$4 = $1;
$5 = $2;
$1 = a;
$2 = b;
$3 = c;
print
}' inputfile
执行$1 = $1
会强制使用新的OFS
重新组合该行。
答案 2 :(得分:0)
awk
(和tr
)解决方案,不是特别优雅:
awk 'BEGIN { OFS = ","}
{ if (NF == 5) {
split($0, a); print $1, $2, $3, $4, $5
} else {
print a[1], a[2], a[3], $1, $2
} }' | tr -d ' \t'
答案 3 :(得分:0)
假设文件以制表符分隔。
您可以迭代每一行,并将split("\t")
应用于每一行,例如
for line in lines:
result = line.split("\t")
如果len(结果)是5,那么你点了一个新的部分。您可以按原样解压缩值
h1, h2, h3, v1, v2 = result
否则,它是
v1, v2 = result
然后,您可以使用",".join([h1, h2, h3, v1, v2])
打印出变量。
至于第二个问题,没有看到文件中的不可见字符,很难分辨。例如,您可以在vi中使用“set list”来查看它们。
答案 4 :(得分:0)
使用awk:
awk 'BEGIN {OFS=","} /^[^ ]/ {f1=$1; f2=$2; f3=$3; f4=$4; f5=$5} /^[ ]/ {f4=$1; f5=$2} {print f1,f2,f3,f4,f5}' < input.txt
答案 5 :(得分:0)
使用awk:
awk 'BEGIN{OFS="\t";} NF==2{print a,b,c,$1,$2}{};NF==5{a=$1; b=$2; c=$3;print $1,$2,$3,$4,$5}{}' logfile
首先将输出字段分隔符设置为选项卡(您可以根据需要更改它),然后查看该行中有多少列。如果有5,则将前三个设置为等于变量a,b和c,然后将它们全部打印出来。
如果只有两列,则打印a,b和c(即最后一行的前三列),然后是该行的两列。
<强>更新强>
我没有注意到只有三列的线!下面的awk命令应该按照您的指定输出:
awk 'BEGIN{OFS="\t";} $1~/^[a-z]/{a=$1; b=$2; c=$3;print $1,$2,$3,$4,$5}{}$1!~/^[a-z]/{print a,b,c,$1,$2}{}' logfile
这与之前的工作方式类似,但会查看第一个字段是以字母开头而不是查看列数。如果需要,可以使这个正则表达式更具体。
答案 6 :(得分:0)
你可以尝试这样的事情来开始 -
awk 'NF>3{a=$1;b=$2;c=$3;$1=$1;print;next}NF<3{d=$1;e=$2;print a,b,c,d,e;next}{$1=$1;}1' OFS=',' file
答案 7 :(得分:-1)
一个简单的grep就可以做到
$ cat so.txt
xyz123 2.000 -0.3974 0.0 hij123
6.0 lmn123
8.7 efg123
13.9 uvw123
28.5 rst123
abc123 10.000 0.1943 0.0 wxy123
10.7 xyz123
19.9 pqr123
20.6 stu123
20.6 klm123
def123 50.000 -0.2595 19.2 jkl123
26.1 stu123
27.1 def123
27.1 ghi123
27.6 abc123
$ cat so.txt | grep "-"
xyz123 2.000 -0.3974 0.0 hij123
def123 50.000 -0.2595 19.2 jkl123