我使用python 3
好的,我有一个像这样锁定的文件:
id:1
1
34
22
52
id:2
1
23
22
31
id:3
2
12
3
31
id:4
1
21
22
11
如何仅查找和删除文件的这一部分?
id:2
1
23
22
31
我一直在努力做到这一点,但无法让它发挥作用。
我使用python 3
好的,我有一个像这样锁定的文件:
id:1
1
34
22
52
id:2
1
23
22
31
id:3
2
12
3
31
id:4
1
21
22
11
如何仅查找和删除文件的这一部分?
id:2
1
23
22
31
我一直在努力做到这一点,但无法让它发挥作用。
是用于决定删除序列的 id,还是用于决定的值列表?
您可以构建一个字典,其中 id 号是键(由于稍后的排序而转换为 int),以下行将转换为作为键值的字符串列表。然后可以删除key为2的item,遍历key排序的item,输出新的id:key加上格式化后的字符串列表。
或者,您可以构建订单受保护的列表列表。如果要保护 id 的序列(即不重新编号),您还可以记住内部列表中的 id:n。
对于大小合理的文件,可以这样做。如果文件很大,您应该将源文件复制到目标文件并即时跳过不需要的序列。对于小文件,最后一种情况也相当容易。
[澄清后添加]
我建议学习以下在许多此类情况下有用的方法。它使用所谓的有限自动机来实现绑定到从一种状态转换到另一种状态的动作(参见Mealy 机器)。
文本行是这里的输入元素。表示上下文状态的节点在此处编号。(我的经验是不值得给它们起名字——让它们只是愚蠢的数字。)这里只使用了两种状态,并且status
可以很容易地用布尔变量替换。但是,如果情况变得更复杂,就会导致引入另一个布尔变量,代码变得更容易出错。
代码一开始可能看起来很复杂,但是当您知道可以单独考虑每个代码时,就很容易理解了if status == number
。这是捕获先前处理的提到的上下文。不要试图优化,让代码那样吧。它实际上可以稍后进行人工解码,并且您可以绘制类似于Mealy 机器示例的图片。如果你这样做了,那就更容易理解了。
想要的功能有点笼统——一组被忽略的部分可以作为第一个参数传递:
import re
def filterSections(del_set, fname_in, fname_out):
'''Filtering out the del_set sections from fname_in. Result in fname_out.'''
# The regular expression was chosen for detecting and parsing the id-line.
# It can be done differently, but I consider it just fine and efficient.
rex_id = re.compile(r'^id:(\d+)\s*$')
# Let's open the input and output file. The files will be closed
# automatically.
with open(fname_in) as fin, open(fname_out, 'w') as fout:
status = 1 # initial status -- expecting the id line
for line in fin:
m = rex_id.match(line) # get the match object if it is the id-line
if status == 1: # skipping the non-id lines
if m: # you can also write "if m is not None:"
num_id = int(m.group(1)) # get the numeric value of the id
if num_id in del_set: # if this id should be deleted
status = 1 # or pass (to stay in this status)
else:
fout.write(line) # copy this id-line
status = 2 # to copy the following non-id lines
#else ignore this line (no code needed to ignore it :)
elif status == 2: # copy the non-id lines
if m: # the id-line found
num_id = int(m.group(1)) # get the numeric value of the id
if num_id in del_set: # if this id should be deleted
status = 1 # or pass (to stay in this status)
else:
fout.write(line) # copy this id-line
status = 2 # to copy the following non-id lines
else:
fout.write(line) # copy this non-id line
if __name__ == '__main__':
filterSections( {1, 3}, 'data.txt', 'output.txt')
# or you can write the older set([1, 3]) for the first argument.
这里是给定原始编号的输出 id 行。如果要重新编号这些部分,可以通过简单的修改来完成。尝试代码并询问详细信息。
请注意,有限自动机的功能有限。它们不能用于通常的编程语言,因为它们无法捕获嵌套的成对结构(如双亲)。
PS 从计算机的角度来看,这 7000 行实际上是一个小文件;)
如果两者之间没有任何值会干扰这将起作用....
import fileinput
...
def deleteIdGroup( number ):
deleted = False
for line in fileinput.input( "testid.txt", inplace = 1 ):
line = line.strip( '\n' )
if line.count( "id:" + number ): # > 0
deleted = True;
elif line.count( "id:" ): # > 0
deleted = False;
if not deleted:
print( line )
编辑:
抱歉,这会删除 id:2 和 id:20 ...你可以修改它,以便第一个 if 检查 - line == "id:" + number
将每一行读入一个字符串数组。索引号是行号 - 1。在阅读该行之前检查该行是否等于“id:2”。如果是,则停止读取该行,直到该行等于“id:3”。读取该行后,清除文件并将数组写回文件,直到数组结束。这可能不是最有效的方法,但应该可以。