我有大量以分号分隔的大型数据文件。所有字符串字段都用双引号括起来。在某些文件中,字符串字段中有多余的引号,这会弄乱后续导入数据进行分析的过程(我正在导入 Stata)。
此代码允许我使用 gnu-awk 查看有问题的引号:
echo '"This";"is";1;"line" of" data";""with";"extra quotes""' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")"}; {for ( i=1 ; i<=NF ; i++ ) if ($i ~ /^"(.*".*)+"$/) {print NR, $i}}'
1 "line" of" data"
1 ""with"
1 "extra quotes""
但我不知道如何替换它们。
我原本想手动进行替换,但结果发现有些文件中有几百个匹配项。我知道 awk 的 -sub-、-gsub- 和 -match- 函数,但我不知道如何针对这个特定问题设计搜索和替换。
在上面的例子中,相应的字段应该是,,,,,,,"This"
即:所有分号都是分隔符,并且除了最外面的引号之外的所有引号都应该被删除"is"
。1
"line of data"
"with"
"extra quotes"
我是否应该使用 -sed-,或者 -awk- 是正确的工具?希望你能帮助我!
谢谢,
马蒂斯
答案1
GNU awk
使用and 的一种方式FPAT
:
awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")" } { for (i=1; i<=NF; i++) if (substr($i,0,1) == "\"" && substr($i,length($i),1) == "\"") { gsub(/"/, "", $i); printf "\"%s\"\n", $i } else { gsub(/"/, "", $i); print $i } }'
测试:
echo '"This";"is";1;"line" of" data";""with";"extra quotes""' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")" } { for (i=1; i<=NF; i++) if (substr($i,0,1) == "\"" && substr($i,length($i),1) == "\"") { gsub(/"/, "", $i); printf "\"%s\"\n", $i } else { gsub(/"/, "", $i); print $i } }'
结果:
"This"
"is"
1
"line of data"
"with"
"extra quotes"
一种方法是使用GNU awk
和:FPAT
GNU sed
sed -e '/^".*"$/ { s/"//g; s/.*/"&"/ }' -e '/^".*"$/!s/"//g'
测试:
echo '"This";"is";1;"line" of" data";""with";"extra quotes""' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")" } { for (i=1; i<=NF; i++) print $i }' | sed -e '/^".*"$/ { s/"//g; s/.*/"&"/ }' -e '/^".*"$/!s/"//g'
结果:
"This"
"is"
1
"line of data"
"with"
"extra quotes"
答案2
我宁愿使用 coreutils 和 sed (GNU 版本):
<<< '"This";"is";1;"line" of" data";""with";"extra quotes""' \
| tr ';' '\n' | sed -r 's/(.)"(.)/\1\2/g' | tr '\n' ';'
输出:
"This";"is";1;"line of data";"with";"extra quotes";
它留下一个额外的分号,并删除换行符,head -c -1
在第二个分号之前插入并附tr
加以; echo
修复:
tr ';' '\n' | sed -r 's/(.)"(.)/\1\2/g' | head -c -1 | tr '\n' ';'; echo
输出:
"This";"is";1;"line of data";"with";"extra quotes"
答案3
我自己的解决方案是仅使用sed
,去掉所有不与分隔符或数字字段并列的分号(该awk
命令只是为了说明清楚):
echo '"This";"is";1;"line" of" data";""without";"extra quotes""' | sed -E 's/([^;])"+([^;])/\1\2/g' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")"}; {for ( i=1 ; i<=NF ; i++ ) print $i}'
"This"
"is"
1
"line of data"
"without"
"extra quotes"
我认为它更快,因为它在整行上工作,而不是按字段分割行。