看起来像一个简单的,但我已经玩了一会儿,找不到优雅的东西!
所以我有这样的数据:
Field1 09:30
Field2 H
Field3 Happy
Field1 09:35
Field3 Sad
Field1 09:40
Field2 C
Field1 09:45
Field2 P
Field3 Pleased
...基本上Field1将始终存在,其他字段是可选的。我想把它剥离成一个csv(遗憾的是我不能使用python)以便适当地留下空格
09:30, H, Happy
09:35, , Sad
09:40, C,
09:45, P, Pleased
答案 0 :(得分:4)
让我们试试这个:
awk 'BEGIN{OFS=", "}
p && /Field1/
{ print a["Field1"], a["Field2"], a["Field3"];
a["Field1"]=a["Field2"]=a["Field3"]=""
}
{a[$1]=$2; p=1}
END{print a["Field1"], a["Field2"], a["Field3"]}
' file
它返回:
$ awk 'BEGIN{OFS=", "} p && /Field1/ {print a["Field1"], a["Field2"], a["Field3"]; a["Field1"]=a["Field2"]=a["Field3"]=""} {a[$1]=$2; p=1} END{print a["Field1"], a["Field2"], a["Field3"]}' file
09:30, H, Happy
09:35, , Sad
09:40, C,
09:45, P, Pleased
BEGIN{OFS=", "}
将输出字段分隔符设置为,
(逗号,空格)。p && /Field1/ {}
如果p
标记为“on”且该行包含Field1
,请执行{}
print a["Field1"], a["Field2"], a["Field3"];
打印a[]
数组的三个值。a["Field1"]=a["Field2"]=a["Field3"]=""
清空数组。{a[$1]=$2; p=1}
,将第二列值存储在a[]
数组中。此外,激活p
标记,以便在找到下一个Field1
时开始打印行。END{print a["Field1"], a["Field2"], a["Field3"]}
打印最后一段数据。答案 1 :(得分:3)
以下是perl
中的解决方案:
perl -lane 'if(/Field([\d])/){
if($1==1 && $.!=1)
{
print join ",",@a;
undef @a
}
$a[$1-1]=$F[1]}
END{print join ",",@a}' your_file
/Field([\d])/
- [\ d]周围的大括号将捕获$ 1中的数字,以后可以用作数组索引。
$a[$1-1]=$F[1]->
将先前捕获的索引中的第二个字段存储在数组中。
if($1==1 && $.!=1)
{
print join ",",@a;
undef @a
}#
一旦捕获的小数为1就打印数组并清空数组。
将在最后留下一个数组,这些数组将打印在END
块中。
下面测试:
> cat temp
Field1 09:30
Field2 H
Field3 Happy
Field1 09:35
Field3 Sad
Field1 09:40
Field2 C
Field1 09:45
Field2 P
Field3 Pleased
> perl -lane 'if(/Field([\d])/){if($1==1 && $.!=1){print join ",",@a;undef @a }$a[$1-1]=$F[1]}END{print join ",",@a}' temp
09:30,H,Happy
09:35,,Sad
09:40,C
09:45,P,Pleased
>
答案 2 :(得分:1)
以下是awk
的替代方案:
# new records always starting with Field1
/Field1/ {
# print record if it isset
if(length(r[0])>0) {
printf "%s, %s, %s\n", r[0], r[1], r[2]
};
# reinitialize record
r[0]=r[1]=r[2]=""
# copy value
r[0]=$2
}
/Field2/ {
# copy value
r[1]=$2
}
/Field3/ {
# copy value
r[2]=$2
}
# the END block idea comes from @fedorqui. Thanks!
END {
# print record if it isset
if(length(r[0])>0) {
printf "%s, %s, %s\n", r[0], r[1], r[2]
};
}
将脚本保存在csv.awk
中。然后像这样执行awk
:
awk -f csv.awk input.txt
答案 3 :(得分:0)
似乎你厌倦了像我一样的数据格式化工作。
下面是我使用了很多,略有修改的片段。您可以在第2行中定义任意数量的字段(不一定是相同的模式),然后发出awk -f so.awk input.txt
(假设您将此awk片段保存在so.awk中,输入文件为input.txt)。
享受:)
EGIN {
FIELD_LIST = "Field1,Field2,Field3"; # fields definition, in order
split(FIELD_LIST, fields, ",");
}
{
pos = find(fields, $1);
if (pos == 0) {
print("unexpected field " $1);
exit 1;
}
if ($1 == fields[1] && NR>1) { # record start
echo_record(fields, rec);
split("", rec)
}
rec[$1] = $2; # store field value
}
END {
echo_record(fields, rec);
}
# find position of val in arr. 0 if not found
function find(arr, val)
{
i=1;
for (idx in arr) {
if (arr[idx] == val) return i;
++i;
}
return 0;
}
function echo_record(fileds, record)
{
start = 0
for (key in fields) {
if (start) printf(", ");
start = 1;
val = record[fields[key]];
if (val) printf("%s", val);
else printf(" ");
}
printf("\n");
}
答案 4 :(得分:0)
再一次。
function dump() { if (a[1]!="") print a[1],a[2],a[3]; a[2]=a[3]=""; };
BEGIN { RS="Field"; OFS=", "; a[1]=a[2]=a[3]="" }
END {dump()}
{ if ($1=="1") dump(); a[$1]=$2; }