如果分隔符也存在于文件中任何位置的字段数据中,如何替换分隔符?

时间:2016-09-14 21:55:55

标签: linux csv sed

我在linux中有输入文件的内容,比如

test1|2|2||0|Sun,day|Jan
be,st3|1|0||0|Sunday|Feb1
nest|0|0||0|Sunday|Jul
rest,5||||0|Sunday|Aug

需要像

这样的输出
    ax2.legend(self.labels,colorList[:len(self.labels)])
    plt.legend()

使用tr命令用|替换它也取代了fieldvalue。我无法理解如何仅更改分隔符而不更改值。有人可以提供一些指示我可以用来执行此任务的命令和命令吗?

3 个答案:

答案 0 :(得分:3)

使用sed:

$ sed -E ':a; s/^(([^"]*("[^"]*")?)*),/\1|/; ta; s/"//g' file
test1|2|2||0|Sun,day|Jan
be,st3|1|0||0|Sunday|Feb1
nest|0|0||0|Sunday|Jul
rest,5||||0|Sunday|Aug

如何运作

如果,出现在偶数|之后,则,会更改为"

  • :a

    这定义了标签a

  • s/^(([^"]*("[^"]*")?)*),/\1|/

    从行的开头^开始,这将查找以下任意数量的序列:

    1. `[^"]*`  = zero or more non-quotes
    
    2. `("[^"]*")?`  = pairs of quotes
    
  • ta

    如果之前的s命令导致替换成功,则跳回标签a并重试。

  • s/"//g

    在我们用竖条替换所有未加引号的逗号后,我们删除了引号。

简化

正如Potong所指出的,另一种更简单的解决方案是:

sed -E 's/(([^,"]*("[^"]*")*)*),/\1|/g;s/"//g' file

这是因为两个细微之处:(1)sed的正则表达式寻找最左边最长的匹配,(2)当进行全局(g)替换时,后续匹配不允许与先前的匹配重叠。考虑到这两个规则,此命令仅在偶数引号后用,替换|

答案 1 :(得分:2)

使用sed实现这是一项艰巨的任务。

另一方面,在python(版本3.x)中,完成了几行:

import csv

with open("input.csv") as fr:
    with open("output.csv","w",newline='') as fw:  # uncomment for python 3.x
    with open("output.csv","wb") as fw:            # python 2.x only
        cr = csv.reader(fr,delimiter=",")
        cw = csv.writer(fw,delimiter="|")
        cw.writerows(cr)

工作原理:它只使用了惊人的内置csv模块。用分隔符读取,用另一个写入。

好的,现在只是为了好玩...我的sed解决方案,如果你真的想知道

创建一个这样的sedfile:

s/"\([^",]\+\)"/\1/g
s/"\([^"]\+\),\([^"]\+\)"/\1%\2/g
s/,/\|/g
s/%/,/g

应用它sed -f sedfile.txt input.csv > output.csv

它如何运作:

  • 从简单字段中删除引号
  • 从包含逗号的字段中删除引号,但用百分号替换逗号
  • 更改分隔符
  • 通过昏迷改变百分号

结果:

test1|2|2||0|Sun,day|Jan
be,st3|1|0||0|Sunday|Feb1
nest|0|0||0|Sunday|Jul
rest,5||||0|Sunday|Aug

每个受保护字段限制为1个昏迷(可以扩展到3个或更多......),字段不得使用%符号。

答案 2 :(得分:1)

"(?<a>[^"]+)",
    {li> "" ,内的文字(后面紧跟a)被捕获在命名组(?<a>[^,]*),
  • ,,结尾的a以外的文字也会在命名组%+
  • 中捕获
  • 可以通过哈希"(?<a>[^"]+)",
  • 访问指定的组
  • 顺序很重要 - "Sep"首先在评估备用正则表达式之前完成
  • 注意:如果引用了最终元素,请说named capture,则不会删除引号


进一步阅读: perlre - 搜索shutdown_hook