我有一个CSV,我需要重新格式化单个列的内容。 问题是每个单元格的长度完全不同,需要重新格式化。
当前列看起来像(这是两列单列):
Foo*foo*foo*1970,1980+Bar*bar*bar*1970
Foobar*Foobar*foobarbar*1970,1975,1980
结果看起来像(仍然是两行一列)
Foo*foo*foo*1970+Foo*foo*foo*1980+Bar*bar*bar*1970
Foobar*Foobar*foobarbar*1970+Foobar*Foobar*foobarbar*1975+Foobar*Foobar*foobarbar*1980
这就是我想要做的事情
#!/bin/bash
cat foocol | \
awk -F'+' \
'{for i in NF print $i}' \
| awk -F'*' \
'{$Foo=$1"*"$2"*"$3"*" print $4}' \
\
| awk -v Foo=$Foo -F',' \
'{for j in NF do \
print Foo""$j"+" }' \
> newcol
这个想法是迭代多个' +'分隔数据,而前三个' *'定界值将按每个''进行分组。分隔年份,用' +'他们之间
但我到处都是语法错误。
由于
答案 0 :(得分:1)
$ awk --re-interval -F, -v OFS=+ '{match($1,/([^*]*\*){3}/);
prefix=substr($0,RSTART,RLENGTH);
for(i=2;i<=NF;i++) $i=prefix $i }1' file
Foo*foo*foo*1970+Foo*foo*foo*1980+Bar*bar*bar*1970
Foobar*Foobar*foobarbar*1970+Foobar*Foobar*foobarbar*1975+Foobar*Foobar*foobarbar*1980
或许可以使用if(match(...
答案 1 :(得分:1)
TXR中的解决方案:
$ txr reformat.txr data Foo*foo*foo*1970+Foo*foo*foo*1980+Bar*bar*bar*1970 Foobar*Foobar*foobarbar*1970+Foobar*Foobar*foobarbar*1975+Foobar*Foobar*foobarbar*1980
reformat.txr
中的代码:
@(repeat)
@ (coll)@/\+?/@a*@b*@c*@(coll)@{x /[^,+]+/}@(until)+@(end)@(end)
@ (output :into items)
@ (repeat)
@ (repeat)
@a*@b*@c*@x
@ (end)
@ (end)
@ (end)
@ (output)
@ {items "+"}
@ (end)
@(end)
此解决方案基于具有嵌套语法的数据:记录组由换行符分隔。组内的记录由+
分隔,在记录中有四个以*
分隔的字段。最后一个字段包含以逗号分隔的项目。通过扩展记录副本来规范化数据,使逗号分隔的项目分布在副本中。
外部@(repeat)
手柄越过线条。外部@(coll)
遍历记录,将前三个字段收集到变量a
,b
和c
中。然后内部@(coll)
将每个逗号分隔的项目放入变量x
。内部@(coll)
将x
- s收集到一个列表中,外部@(coll)
也将所有变量收集到列表中,因此a
,b
,{ {1}}成为字符串列表,c
是字符串列表的列表。
x
中的:into items
关键字参数会导致通常将标准输出设备的行收集到字符串列表中,并绑定到变量。例如:
output
建立一个变量@(output :into lines)
a
b
cd
@(end)
,其中包含列表lines
。
所以这里我们将双嵌套("a" "b" "cd")
的输出作为一堆行,其中每一行代表一条记录,存储在一个名为repeat
的变量中。然后我们items
使用output
,这是一种语法,用给定的分隔符输出列表变量的内容。
双重嵌套@{items "+"}
处理每个逗号分隔项与第四个字段的记录扩展。外部repeat
隐式迭代列表repeat
,a
,b
和c
。在x
内,这些变量表示各自列表中的项目。变量repeat
是一个列表列表,因此内部x
会对其进行迭代。在外部repeat
内,变量repeat
,a
,b
已经是标量,并且保持在内部c
的范围内:仅repeat
1}}变化,这正是我们想要的。
在每行的数据收集中,有一些细微之处:
x
首先,我们将可选的前导加上与@ (coll)@/\+?/@a*@b*@c*@(coll)@{x /[^,+]+/}@(until)+@(end)@(end)
正则表达式匹配,从而消耗它。如果没有这个,除了第一个记录之外,每个记录的/\+?/
字段将包括分隔a
,我们将在最终输出中得到双+
- s。简单地匹配+
,a
,b
变量。 TXR对于分隔材料非贪婪:c
表示将某些字符与最近的@a*
匹配,并将它们绑定到变量*
。收集a
列表更加棘手。这里使用正 - 正则表达式匹配变量:x
来提取子字段。每个@{x /[^,+]+/}
是一个或多个字符的序列,这些字符不是加号或逗号,在不考虑后续内容的情况下正向提取,就像标记器提取标记一样。此内部集合在遇到x
时终止,这是+
子句确保的内容。如果它到达行尾,它也会隐式终止; @(until)+
匹配不是强制性的(默认情况下)。终止@(until)
会停留在输入流中,这就是为什么我们必须识别它并将其丢弃在+
前面。
应该注意的是,默认情况下,@a
会扫描匹配项并跳过不匹配的文本区域,就像它的堂兄@(coll)
一样。例如,如果我们有@(collect)
,它会将小写字母序列收集到@(coll)@{foo /[a-z]+/}@(end)
中,将foo
转换为此类字符串列表,如果输入为foo
,然后1234abcd-efgh.... ijk
以foo
列表结束。这就是为什么内部("abcd" "efgh" "ijk")
中没有明确的逻辑来使用分隔逗号:它们被隐式跳过。