如何从csv文件中删除多行重复行?

时间:2019-05-23 02:12:57

标签: python csv unix sed

我正在处理一个csv文件,该文件是气相色谱数据分析仪的输出,因此我只能操作所提供的文件。我需要从csv文件中删除不必要的行或仅保留必要的行。实际文件中有960行。

文件中的第1 8行看起来像这样

[Line 1]  Remove
[Line 2]  Remove
[Line 3]  Keep
[Line 4]  Remove
[Line 5]  Remove
[Line 6]  Remove
[Line 7]  Keep
[Line 8]  Keep

我要保留/删除的行范围的模式会持续数百行,因此这里以接下来的8行为例。

[Line 9]   Remove
[Line 10]  Remove
[Line 11]  Keep
[Line 12]  Remove
[Line 13]  Remove
[Line 14]  Remove
[Line 15]  Keep
[Line 16]  Keep

没有字符串模式只能识别行号本身。我想避免不得不计算数百行的范围,并将它们全部放入sed中,如下面所示的脚本,该脚本仅在前8行中就减少了所需的行数。

    sed '1,2d; 4,6d' test.csv >> cut_test.csv

我希望以下几点:

[Line 3]  Keep
[Line 7]  Keep
[Line 8]  Keep
[Line 11] Keep
[Line 15] Keep
[Line 16] Keep

5 个答案:

答案 0 :(得分:5)

如果要保留的行号遵循您在说明中提供的确切模式(每8行重复一次),则可以使用以下GNU sed命令:

$ sed '1~8d;2~8d;4~8d;5~8d;6~8d;' input.csv 
[Line 3]  Keep
[Line 7]  Keep
[Line 8]  Keep
[Line 11]  Keep
[Line 15]  Keep
[Line 16]  Keep

并将其重定向到新文件或用户-i.back,以就地更改文件。

说明:

  • 1~8d将在第一行,第9行...上执行d命令。
  • 2~8d将在第二行,第十行,...上执行d命令。

input.csv:

$ cat input.csv 
[Line 1]  Remove
[Line 2]  Remove
[Line 3]  Keep
[Line 4]  Remove
[Line 5]  Remove
[Line 6]  Remove
[Line 7]  Keep
[Line 8]  Keep
[Line 9]   Remove
[Line 10]  Remove
[Line 11]  Keep
[Line 12]  Remove
[Line 13]  Remove
[Line 14]  Remove
[Line 15]  Keep
[Line 16]  Keep

您甚至可以通过以下方式重新组合所有内容来简化命令(这与您的命令很接近):

$ sed '1~8,2~8d;4~8,6~8d;' input.csv 
[Line 3]  Keep
[Line 7]  Keep
[Line 8]  Keep
[Line 11]  Keep
[Line 15]  Keep
[Line 16]  Keep

Thor所述,如果仅打印要保留的行而不是删除要删除的行,则可以减少命令:

$ sed -n '3~8p;7~8,8~8p;' input.csv
[Line 3]  Keep
[Line 7]  Keep
[Line 8]  Keep
[Line 11]  Keep
[Line 15]  Keep
[Line 16]  Keep

答案 1 :(得分:3)

Python方法就是

import sys
for i,l in enumerate(sys.stdin):
  if i%8 in (2,6,7): print(l)  # 0-based

答案 2 :(得分:1)

sed解决方案很优雅,但是正如您还标记了Python一样,这是该语言的等效解决方案。如果有必要,它应该扩展到巨大的文件,因为它永远不会一次读取整个文件(我相信sed解决方案也是如此)

import itertools

with open('input.csv', 'r') as in_file:
    with open('output.csv', 'w') as out_file:
        out_file.writelines(entry for entry, keep in zip(in_file.readlines(), itertools.cycle([False, False, True, False, False, False, True, True])) if keep)

答案 3 :(得分:1)

简短答案

awk中针对匹配项的默认操作是打印该行:     awk'NR%8〜/ 3 | 7 | 0 /'input.csv

详细答案,受@kvantour的评论启发

awk 'NR%8~/3|7|0/' input.csv
# or shorter (when module < 10)
awk 'NR%8~/[037]/' input.csv

当需要模数> 9时,需要将整行与^$标记匹配。使用模25和第3、7、8、11、14、22行,您可以使用

awk 'NR%25~/^[3|7|0|11|14|22]$/' input.csv
# or shorter
awk 'NR%25~/^[037]|1[14]|22$/' input.csv

要获取更多值,将变得很难阅读。替代方法是

# Original case
awk 'BEGIN {a[3];a[7];a[0]} NR%8 in a' input.csv 
# 3,7,8,11,14,22
awk 'BEGIN {a[3];a[7];a[8];a[11];a[14];a[22];} NR%25 in a' input.csv 

将数字拉出:

# Original case
awk 'FNR==NR {a[$0];next} FNR%8 in a' <(printf "%s\n" 3 7 0) input.csv 
# 3,7,8,11,14,22
awk 'FNR==NR {a[$0];next} FNR%25 in a' <(printf "%s\n" 3 7 8 11 14 22) input.csv 

答案 4 :(得分:1)

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

sed -n 'n;n;p;n;n;n;n;p;n;p' file

按照罐头上的说明做。

更好(Thor已经提到):

sed -n '3~8p;7~8,+1p' file