我有一个以逗号分隔的文件,其中包含数字列和字符串列。字符串列被引用,并且引号之间可以有逗号。如何识别带有 的列FS =","
?
样本记录
"prabhat,kumar",19,2000,"bangalore,India"
在AWK它应该是
$1 = "prabhat,kumar"
$2 = 19
$3 = "2000"
$4 = "bangalore,india"
设置FS=","
正在创造问题。
输入是:
"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"
"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"
输出应该是:
"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"
"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"
我正在尝试的代码:
awk -F"," '{for(i=1;i<=NF;i++){if(i%NF==0){ORS="\n"} {if($i ~ /^\"/ || $i ~ /\"$/) {a=a OFS $i;j++;{if(j%2==0){sub(/^\,/,X,a); print a;j=0;a=""}}} else {print $i}}} {ORS="|"}}' ORS="|" OFS=, p.txt
答案1
首先,您应该使用合适的 CSV 解析器。例如,在 Perl 中,您可以使用Text::CSV
:
安装
cpanm
(如果你使用 Perl,稍后你会感谢我的)$ sudo apt-get install cpanminus
如果您使用的不是基于 Debian 的系统,您应该能够使用您的发行版的包管理器来安装它。
安装
Text::CSV
模块$ sudo cpanm Text::CSV
解析你的文件
$ perl -MText::CSV -le ' $csv = Text::CSV->new({binary=>1}); while ($row = $csv->getline(STDIN)){ print "1:$row->[0], 2:$row->[1], 3:$row->[2], 4:$row->[3]"}' < file.csv 1:prabhat,kumar, 2:19, 3:2000, 4:bangalore,India
正如您在上面看到的,第一个字段是
$row->[0]
,第二个字段$row->[1]
等等。
这是正确的方法。一个更简单但肮脏的技巧是将任何引用的逗号替换为另一个字符。然后,正常使用awk
,最后再次将它们切换回逗号。我在这里使用###
,但你可以使用任何你确信永远不会出现在你的领域之一的东西。
$ sed -r 's/("[^",]+),([^",]+")/\1###\2/g' file.csv |
awk -F, '{print $1,$3}' | sed 's/###/,/g'
"prabhat,kumar" 2000
答案2
如果你有 GNU awk
:
$ awk -vFPAT='[^,]*|"[^"]*"' '{ gsub("^\"|\"$","",$1); gsub("^\"|\"$","",$4); print $1 $4} '
prabhat,kumarbangalore,India
输出格式有点难看,因为我只打印$1
并且$4
彼此相邻 - 我相信您可以根据自己的口味更改它。
如果您需要保留字段周围的双引号,请删除这两个gsub();
函数。
解释:
通常,awk
通过(字段分隔符)变量的内容分隔记录中的字段 FS
,该变量默认为任何空白(制表符、空格和换行符)。分隔符告诉awk
记录的结束位置。在csv
文件中,记录以逗号结尾(传递给awk
as -vFS=,
),但是当然,在与您类似的示例中,这太简单了并且会损坏。
或者,FPAT
(字段模式)定义 中的记录awk
。您无需指定awk
记录的结束位置,而是创建包含整个记录的定义。在你的例子的复杂中csv
,这是[^,]*|"[^"]*"
细分如下:-
[^,]
尽可能多地出现非逗号 ( ) 的字符(*
)。两个逗号之间的所有内容都是一个字段。- 或者 (
|
) - 一个单双引号 (
"
) 后跟无双引号 ([^"]
) 的次数尽可能多 (*
) 后跟一个单双引号 ("
)。双引号内的所有内容(包括逗号)均算作一个字段。
答案3
Ruby 对于 CSV 解析很方便:
ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|")' file
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS
请注意,输出中没有引号。这是因为没有任何字段包含字段分隔符。如果需要引号,可以强制引用所有字段(甚至整数):
ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|",:force_quotes=>true)' file
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"
答案4
这对我有用:
$ echo '"prabhat,kumar",19,2000,"bangalore,India"' |
awk -F, '{print $1,$2,$3,$4,$5,$6}'|
awk -F\" '{print $2,$3,$4}'|awk -F\ '{print $1","$2,$3,$4,$5","$6}'`