使用grep -o或sed(或其他)替换字符,除了模式之间

时间:2019-07-19 12:49:45

标签: awk sed grep

在以下文件中,我希望将所有;替换为,,不同之处在于,当有一个字符串(以两个"分隔)时,不应替换;

示例: 输入

A;B;C;D
5cc0714b9b69581f14f6427f;5cc0714b9b69581f14f6428e;1;"5cc0714b9b69581f14f6427f;16a4fba8d13";xpto;
5cc0723b9b69581f14f64285;5cc0723b9b69581f14f64294;2;"5cc0723b9b69581f14f64285;16a4fbe3855";xpto;
5cc072579b69581f14f6428a;5cc072579b69581f14f64299;3;"5cc072579b69581f14f6428a;16a4fbea632";xpto;

输出

A,B,C,D
5cc0714b9b69581f14f6427f,5cc0714b9b69581f14f6428e,1,"5cc0714b9b69581f14f6427f;16a4fba8d13",xpto,
5cc0723b9b69581f14f64285,5cc0723b9b69581f14f64294,2,"5cc0723b9b69581f14f64285;16a4fbe3855",xpto,
5cc072579b69581f14f6428a,5cc072579b69581f14f64299,3,"5cc072579b69581f14f6428a;16a4fbea632",xpto,

对于sed,我有:sed 's/;/,/g' input.txt > output.txt,但这将取代所有内容。

"分隔字符串的正则表达式:\".*;.*\"

(十六进制的正则表达式会更好-类似于:[0-9a-fA-F]+

我的问题是将所有内容组合在一起,以制作一个grep -o / sed替换该模式以外的所有内容。

文件大小约为两位数Gb(最大99Gb),因此performance is important. Relevant

任何想法都值得赞赏。

3 个答案:

答案 0 :(得分:1)

sed用于对单个字符串执行简单的s/old/newgrep用于执行g/re/p。您没有尝试执行这些任务中的任何一个,因此您不应该考虑这些工具中的任何一个。剩下另一个用于处理文本的标准UNIX工具-awk

您有一个用;分隔的,分隔的CSV。就是这样:

$ awk -v FPAT='[^;]*|"[^"]+"' -v OFS=',' '{$1=$1}1' file
A,B,C,D
5cc0714b9b69581f14f6427f,5cc0714b9b69581f14f6428e,1,"5cc0714b9b69581f14f6427f;16a4fba8d13",xpto,
5cc0723b9b69581f14f64285,5cc0723b9b69581f14f64294,2,"5cc0723b9b69581f14f64285;16a4fbe3855",xpto,
5cc072579b69581f14f6428a,5cc072579b69581f14f64299,3,"5cc072579b69581f14f6428a;16a4fbea632",xpto,

以上将GNU awk用于FPAT。有关使用awk解析CSV的更多详细信息,请参见What's the most robust way to efficiently parse CSV using awk?

答案 1 :(得分:0)

如果我正确地满足了您的要求,一种选择就是制作三关。

根据您对十六进制的评论,我认为输入中不会出现#号,因此您可以这样做(使用GNU sed):

sed -E 's/("[^"]+);([^"]+")/\1#\2/g' original > transformed
sed -i 's/;/,/g' transformed
sed -i 's/#/;/g' transformed

这个想法是用引号将;替换为其他内容并将其写入新文件,然后将所有;替换为,,然后退回{{1 }}放在同一文件中(sed的;标志)。

可以通过以下命令将三遍组合为一个命令

-i

也就是说,可能有很多csv解析器巫婆已经处理了引号字段,您可能会在最终用例中使用该字段,因为我敢打赌,这只是链中其他内容的中间步骤。

根据Ed Morton的评论:如果您一次性完成,可以使用sed -E 's/("[^"]+);([^"]+")/\1#\2/g;s/;/,/g;s/#/;/g' original > transformed 作为替换分隔符,因为在逐行考虑的文本中没有换行符。

答案 2 :(得分:0)

这可能对您有用(GNU sed):

sed -E ':a;s/^([^"]*("[^"]*"[^"]*)*"[^";]*);/\1\n/;ta;y/;/,/;y/\n/;/' file

用换行符替换;内的双引号,将;换成,,然后将换行符换成;