我的CSV文件包含以下格式的文本:
"abcd, xyz", abcd, 012
"xyz, 123, abcd", 123, "abcd, pqr"
每列可能都有逗号分隔的文本。在这种情况下,列内的文本被包含在一对“”字符中。
我正在寻求使用sed或awk解析这样一个文件的帮助。
非常感谢你。
答案 0 :(得分:1)
最简单的事情是将引号内的逗号或字段之间的逗号转换为其他字符,例如:这会将字段之间的每个“,”转换为制表符char:
$ awk 'BEGIN{FS=OFS="\""} {for (i=1;i<=NF;i+=2) gsub(/[[:space:]]*,[[:space:]]*/,"\t",$i)} 1' file
"abcd, xyz" abcd 012
"xyz, 123, abcd" 123 "abcd, pqr"
然后当然你需要找到一些在输入中不会出现的字符,这样你就可以选择一个控件字符或SUBSEP或其他东西。
或者,这会将每个“a”转换为“aA”,并将每个分隔符转换为“aB”,这样您就知道您的分隔符不会出现在您的输入中:
$ awk 'BEGIN{FS=OFS="\""} {gsub(/a/,"aA"); for (i=1;i<=NF;i+=2) gsub(/[[:space:]]*,[[:space:]]*/,"aB",$i)} 1' file
"aAbcd, xyz"aBaAbcdaB012
"xyz, 123, aAbcd"aB123aB"aAbcd, pqr"
你可以这样做:
$ awk 'BEGIN{FS=OFS="\""} {gsub(/a/,"aA"); for (i=1;i<=NF;i+=2) gsub(/[[:space:]]*,[[:space:]]*/,"aB",$i)} 1' file |
awk -F'aB' '{gsub(/aA/,"a"); print $0; for (i=1;i<=NF;i++) print "\tField " i " = <" $i ">"}'
"abcd, xyz"aBabcdaB012
Field 1 = <"abcd, xyz">
Field 2 = <abcd>
Field 3 = <012>
"xyz, 123, abcd"aB123aB"abcd, pqr"
Field 1 = <"xyz, 123, abcd">
Field 2 = <123>
Field 3 = <"abcd, pqr">
如果您想在一个命令中完成所有操作:
$ awk '
function decomma() {
FS = OFS = "\""
$0 = $0
gsub(/a/,"aA")
for (i=1;i<=NF;i+=2)
gsub(/[[:space:]]*,[[:space:]]*/,"aB",$i)
gsub(/aA/,"a")
FS = "aB"
$0 = $0
}
{
print $0
decomma()
for (i=1;i<=NF;i++)
print "\tField " i " = <" $i ">"
}
' file
"abcd, xyz", abcd, 012
Field 1 = <"abcd, xyz">
Field 2 = <abcd>
Field 3 = <012>
"xyz, 123, abcd", 123, "abcd, pqr"
Field 1 = <"xyz, 123, abcd">
Field 2 = <123>
Field 3 = <"abcd, pqr">
答案 1 :(得分:0)
另一种CSV格式如下(唯一引用的字段是包含逗号的字段):
field1, "field2,with,commas" , field3 , "field4,foo"
我们在这里有引用和不引用字段的混合,不能直接通过FS的任何值解析(至少我知道)。但是,我们仍然可以在循环中使用match()来获取字段(并且有点作弊):
c=0
$0=$0"," # yes, cheating
while($0) {
match($0,/ *"[^"]*" *,|[^,]*,/)
f=substr($0,RSTART,RLENGTH) # save what matched in f
gsub(/^ *"?|"? *,$/,"",f) # remove extra stuff
print "Field " ++c " is " f
$0=substr($0,RLENGTH+1) # "consume" what matched
}
上述数据引自:http://web.archive.org/web/20120531065332/http://backreference.org/2010/04/17/csv-parsing-with-awk/