我有一个 CSV 文件,其中一些字段被引用,但引号内的条目由双空格或单空格分隔。我需要将它们替换为逗号。
示例行:
This is okay,"ABC DEF GHI",123,"This is not okay",remove,spaces,within,quotes
以及它应该是什么样子:
This is okay,"ABC,DEF,GHI",123,"This,is,not,okay",remove,spaces,within,quotes
答案1
perl -pe 's/".*?"/do{$a = $&; $a =~ s: +:,:g; $a}/ge;'
本质上,这只是全局正则表达式的替换s/regex/replacement/g
。正则表达式是,它匹配以下一个".*?"
开头和结尾的每个子字符串。棘手的部分是:"
"
- 替换的不是字符串,而是计算的表达式。 (这就是
e
后面修饰符的意思g
。) - 计算的表达式又是一个全局正则表达式替换
s:regex:replacement:g
,它用逗号替换任何非空的空格序列。 (我们不能使用与外部替换相同的分隔符,因此我们使用:
代替/
。) - 为了执行内部正则表达式替换,我们必须将外部替换的匹配子字符串分配
$&
给其他变量$a
,然后执行内部替换$a
,最后打印$a
。
使用足够新的 perl 版本,可以避免对辅助变量的赋值。使用r
修饰符,可以直接在匹配子字符串的副本上执行内部替换$&
(感谢 Stéphane Chazelas):
perl -pe 's/".*?"/$&=~s: +:,:gr/ge;'
答案2
考虑这个暴力的 awk 解决方案:
awk -F, -v OFS=, '
{
for(i=1;i<=NF;i++)
if ($i ~ /^".*"$/)
gsub(" +", ",", $i)
print $0
}'
它告诉 awk 用逗号分割记录 - 请注意,如果您的任何字段包含逗号,这将会中断! -- 并使用 OFS 告诉 print 语句用逗号重新组合字段。循环for
遍历该行的每个字段,如果该字段^
以双引号开头、包含任何字符.*
并$
以双引号结尾,则全局$i
用逗号替换该字段中任意数量的空格。循环遍历字段后,打印整个记录 ( $0
)。
答案3
使用 GNU awk
:
gawk -v RS=\" '
NR % 2 == 0{gsub(/ +/, ",")}
{ORS = RT; print}'
也就是说,记录分隔符"
仅在偶数记录上替换字符和空格。
RT
是 GNU 特定的部分。
与 GNU 相同sed
:
tr '\n"' '"\n' | sed -E '2~2s/ +/,/g' | tr '"\n' '\n"'
更便携:
tr '\n"' '"\n' | sed 'n;s/ */,/g' | tr '"\n' '\n"'
可以与其他一些sed
s 一起使用,但如果输入的最后一个字符不是 则可能会遇到问题"
。