![仅删除逗号分隔文件中引号内嵌入的逗号](https://linux22.com/image/25718/%E4%BB%85%E5%88%A0%E9%99%A4%E9%80%97%E5%8F%B7%E5%88%86%E9%9A%94%E6%96%87%E4%BB%B6%E4%B8%AD%E5%BC%95%E5%8F%B7%E5%86%85%E5%B5%8C%E5%85%A5%E7%9A%84%E9%80%97%E5%8F%B7.png)
我有一个用逗号 ( ) 分隔的输入文件,
。有些字段用双引号引起来,其中有逗号。这是示例行
123,"ABC, DEV 23",345,534.202,NAME
我需要删除双引号内出现的所有逗号以及双引号。所以上面的行应该被解析为如下所示
123,ABC DEV 23,345,534.202,NAME
我尝试了以下使用sed
但没有给出预期结果。
sed -e 's/\(".*\),\(".*\)/\1 \2/g'
sed
或awk
任何其他 UNIX 实用程序有什么快速技巧吗?
答案1
awk
如果引号是平衡的,您将需要删除每个其他引号之间的逗号,可以这样表达:
awk -F'"' -v OFS='' '{ for (i=2; i<=NF; i+=2) gsub(",", "", $i) } 1' infile
输出:
123,ABC DEV 23,345,534.202,NAME
解释
指示-F"
awk 对双引号字符进行字段分割,这意味着所有其他字段都将是引号间文本。 for 循环gsub
在所有其他字段上运行 ,全局替换的缩写,将逗号 ( ","
) 替换为空 ( ""
)。最后1
调用默认代码块:{ print $0 }
。
答案2
有一个好的响应,只需使用 sed 一次环形:
echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME'|
sed ':a;s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /;ta'
123,"ABC DEV 23",345,534,"some more comma-separated words",202,NAME
解释:
:a;
是进一步分支的标签s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /
可以包含 3 个封闭部件- 第一个第二个:
[^"]*,\?\|"[^",]*",\?
匹配不包含双引号的字符串,可能后跟逗号或者由两个双引号括起来的字符串,不带逗号,后面可能有一个逗号。 - 比第一个稀土部分由前面描述的第 2 部分的多次重复组成,后跟 1 个双引号和一些字符,但没有双引号,也没有逗号。
- 第一个 RE 部分后面跟着一个彗差。
- 注意,该行的其余部分不需要触及
- 第一个第二个:
ta
:a
如果之前的s/
命令做了一些更改,则将循环。
循环完成后,您甚至可以添加s/ */ /g
:
echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME'|
sed ':a;s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /;ta;s/ */ /g'
将抑制双空格:
123,"ABC DEV 23",345,534,"some more comma-separated words",202,NAME
答案3
还可以处理平衡引号之间的多个逗号的通用解决方案需要嵌套替换。我在 perl 中实现了一个解决方案,它处理给定输入的每一行,并且仅替换每隔一对引号中的逗号:
perl -pe 's/ " (.+? [^\\]) " # find all non escaped
# quoting pairs
# in a non-greedy way
/ ($ret = $1) =~ (s#,##g); # remove all commas within quotes
$ret # substitute the substitution :)
/gex'
或者简而言之
perl -pe 's/"(.+?[^\\])"/($ret = $1) =~ (s#,##g); $ret/ge'
您可以通过管道将要处理的文本传递给命令,也可以将要处理的文本文件指定为最后一个命令行参数。
答案4
您的第二个引用放错了位置:
sed -e 's/\(".*\),\(.*"\)/\1 \2/g'
此外,使用正则表达式往往会匹配文本的最长可能部分,这意味着如果字符串中有多个带引号的字段,则这将不起作用。
sed 中处理多个引用字段的方法
sed -e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' -e 's/\"//g'
这也是解决此问题的一种方法,但是,对于每个引用字段可能包含多个逗号的输入,sed 中的第一个表达式必须重复与单个字段中的最大逗号内容一样多的次数,或者直到它根本不会改变输出。
使用多个表达式运行 sed 应该比运行多个 sed 进程和所有使用开放管道运行的“tr”更有效。
但是,如果输入格式不正确,这可能会产生不良后果。即嵌套引号、未终止引号。
使用正在运行的示例:
echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME' \
| sed -e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' \
-e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' -e 's/\"//g'
输出:
123,ABC DEV 23,345,534,some more comma-separated words,202,NAME