如何创建文件的副本,其中在 python3 中删除了多个列范围

How to create a copy of a file with multipe ranges of columns removed in python3

我想制作一个文件的副本,其中包含删除了多个数字范围的固定宽度记录。例如,一个文件有固定宽度的记录 1600 长,我想保留列 0-83、89-1517、1526-end。这是为了解决更大的问题,cut 和 awk 等独立实用程序在这里无济于事。

我有这个,我把它应用到每个 line/record;它工作正常,想知道是否有明显更好的东西。

"".join([full[:84], full[89:1518], full[1526:]])

特别是我发现指定要删除的内容比保留的内容更自然,如果有标准库或易于阅读的快速函数更像是

 # hypothetical
 cut(line, [ [84,88], [1519, 25] ])

加法

要接受答案,请使用排序的剪切列表,以便来电者可以按任何顺序给出。最好也添加重叠检测

def cut(line, cuts):
    sorted_cuts = sorted(cuts, key=lambda x: x[0])
    
    return ''.join(line[slice(keep_start, keep_end)]
                   for keep_start, keep_end in zip(
                           [None] + [cut_end for cut_start, cut_end in sorted_cuts],
                           [cut_start for cut_start, cut_end in sorted_cuts] + [None]))


origline = "0123456789"

assert (cut(origline, [[1,2], [3,4]]) ==
        cut(origline, ([3,4], (1,2))) ==
        cut(origline, [[3,4], [1,2]]))

print(cut(origline, [[1,2], [3,4]]))

这是您假设的 cut 函数的实现。

def cut(line, cuts):
    
    return ''.join(line[slice(keep_start, keep_end)]
                   for keep_start, keep_end in zip(
                           [None] + [cut_end for cut_start, cut_end in cuts],
                           [cut_start for cut_start, cut_end in cuts] + [None]))

print(cut('abcdefghijklmnopqrstuvwxyz', [[1,3], [9,10]]))

给出:

adefghiklmnopqrstuvwxyz

bcj 被删减)

所以:

  • 要保留的切片从开始到第一次切割的开始,
  • 要保留的切片从第一次切割结束到第二次切割开始
  • ...
  • 要保留的最后一个切片从最后一次切割的末尾到字符串的末尾

[None] + [cut_end for cut_start, cut_end in cuts] 是要保留的每个切片的开始,在此示例中 [None, 3, 10]

[cut_start for cut_start, cut_end in cuts] + [None] 是要保留的每个切片的末尾,在本例中为 [1, 9, None]

其中 None 表示 start/end 字符串,由 slice 内置函数使用。



注意:要实现您的示例中给出的削减,您将向此 cut 函数提供参数,如下所示:

 cut(line, [[84, 89], [1519, 1526]])

其中每个双元素列表的第二个元素是 剪切结束后的索引,与正常的 python 索引约定保持一致。

如果你真的想要不是必须这样做(为了得到完全你想要的cut函数描述如上),那么在上面的代码中你将替换:

[cut_end for cut_start, cut_end in cuts]

与:

[cut_end + 1 for cut_start, cut_end in cuts]

为方便起见,这里是该函数的完整代码,以及您将在示例中使用的调用代码:

def cut(line, cuts):
    
    return ''.join(line[slice(keep_start, keep_end)]
                   for keep_start, keep_end in zip(
                           [None] + [cut_end + 1 for cut_start, cut_end in cuts],
                           [cut_start for cut_start, cut_end in cuts] + [None]))

print(cut(line, [[84, 88], [1519, 1525]])