Python 恢复嵌套for循环
两个文件。一个有损坏的数据,另一个有修复。破碎的:Python 恢复嵌套for循环,python,for-loop,coding-style,Python,For Loop,Coding Style,两个文件。一个有损坏的数据,另一个有修复。破碎的: ID 0 T5 rat cake ~EOR~ ID 1 T1 wrong segg T2 wrong nacob T4 rat tart ~EOR~ ID 3 T5 rat pudding ~EOR~ ID 4 T1 wrong sausag T2 wrong mspa T3 strawberry tart ~EOR~ ID 6 T5 with some rat in it ~EOR~ 修正: ID 1 T1 eggs T2 bacon
ID 0
T5 rat cake
~EOR~
ID 1
T1 wrong segg
T2 wrong nacob
T4 rat tart
~EOR~
ID 3
T5 rat pudding
~EOR~
ID 4
T1 wrong sausag
T2 wrong mspa
T3 strawberry tart
~EOR~
ID 6
T5 with some rat in it
~EOR~
修正:
ID 1
T1 eggs
T2 bacon
~EOR~
ID 4
T1 sausage
T2 spam
T4 bereft of loif
~EOR~
EOR意味着记录的结束。请注意,断开的文件比修复文件具有更多的记录,修复文件具有要修复的标记(T1、T2等是标记)和要添加的标记。此代码完全执行它应该执行的操作:
# foobar.py
import codecs
source = 'foo.dat'
target = 'bar.dat'
result = 'result.dat'
with codecs.open(source, 'r', 'utf-8_sig') as s, \
codecs.open(target, 'r', 'utf-8_sig') as t, \
codecs.open(result, 'w', 'utf-8_sig') as u:
sID = ST1 = sT2 = sT4 = ''
RecordFound = False
# get source data, record by record
for sline in s:
if sline.startswith('ID '):
sID = sline
if sline.startswith('T1 '):
sT1 = sline
if sline.startswith('T2 '):
sT2 = sline
if sline.startswith('T4 '):
sT4 = sline
if sline.startswith('~EOR~'):
for tline in t:
# copy target file lines, replacing when necesary
if tline == sID:
RecordFound = True
if tline.startswith('T1 ') and RecordFound:
tline = sT1
if tline.startswith('T2 ') and RecordFound:
tline = sT2
if tline.startswith('~EOR~') and RecordFound:
if sT4:
tline = sT4 + tline
RecordFound = False
u.write(tline)
break
u.write(tline)
for tline in t:
u.write(tline)
我正在写一个新文件,因为我不想把另外两个搞砸。第一个外部for循环在修复文件中的最后一条记录上完成。此时,仍有记录要写入目标文件。这就是最后一个for子句的作用
让我烦恼的是,这最后一行隐式地拾取了第一个内部for循环最后一次中断的位置。就好像它应该说“为了t系列的其余部分”。另一方面,我不知道如何用更少(或不是更多)的代码行(使用dicts和您所拥有的东西)来实现这一点。我应该担心吗
请评论
# building initial storage
content = {}
record = {}
order = []
current = None
with open('broken.file', 'r') as f:
for line in f:
items = line.split(' ', 1)
try:
key, value = items
except:
key, = items
value = None
if key == 'ID':
current = value
order.append(current)
content[current] = record = {}
elif key == '~EOR~':
current = None
record = {}
else:
record[key] = value
# patching
with open('patches.file', 'r') as f:
for line in f:
items = line.split(' ', 1)
try:
key, value = items
except:
key, = items
value = None
if key == 'ID':
current = value
record = content[current] # updates existing records only!
# if there is no such id -> raises
# alternatively you may check and add them to the end of list
# if current in content:
# record = content[current]
# else:
# order.append(current)
# content[current] = record = {}
elif key == '~EOR~':
current = None
record = {}
else:
record[key] = value
# patched!
# write-out
with open('output.file', 'w') as f:
for current in order:
out.write('ID '+current+'\n')
record = content[current]
for key in sorted(record.keys()):
out.write(key + ' ' + (record[key] or '') + '\n')
# job's done
有问题吗?我不会担心的。在您的示例中,
t
是一个文件句柄,您正在对其进行迭代。Python中的文件句柄是它们自己的迭代器;它们具有关于在文件中读取位置的状态信息,并且在您对它们进行迭代时将保留它们的位置。您可以查看python文档以了解更多信息
另请参阅另一个同样涉及迭代器的SO答案:。那里有很多有用的信息
编辑:这里有另一种使用字典组合它们的方法。如果要在输出之前对记录进行其他修改,则可能需要此方法:
import sys
def get_records(source_lines):
records = {}
current_id = None
for line in source_lines:
if line.startswith('~EOR~'):
continue
# Split the line up on the first space
tag, val = [l.rstrip() for l in line.split(' ', 1)]
if tag == 'ID':
current_id = val
records[current_id] = {}
else:
records[current_id][tag] = val
return records
if __name__ == "__main__":
with open(sys.argv[1]) as f:
broken = get_records(f)
with open(sys.argv[2]) as f:
fixed = get_records(f)
# Merge the broken and fixed records
repaired = broken
for id in fixed.keys():
repaired[id] = dict(broken[id].items() + fixed[id].items())
with open(sys.argv[3], 'w') as f:
for id, tags in sorted(repaired.items()):
f.write('ID {}\n'.format(id))
for tag, val in sorted(tags.items()):
f.write('{} {}\n'.format(tag, val))
f.write('~EOR~\n')
dict(断开的[id].items()+固定的[id].items())
部分利用了这一点:
为了完整起见,为了分享我的热情和我学到的东西,下面是我现在使用的代码。它回答了我的问题,还有更多 这部分是基于上述akaRem的方法。一个函数填充一个dict。它被调用两次,一次用于修复文件,一次用于修复文件
import codecs, collections
from GetInfiles import *
sourcefile, targetfile = GetInfiles('dat')
# GetInfiles reads two input parameters from the command line,
# verifies they exist as files with the right extension,
# and then returns their names. Code not included here.
resultfile = targetfile[:-4] + '_result.dat'
def recordlist(infile):
record = collections.OrderedDict()
reclist = []
with codecs.open(infile, 'r', 'utf-8_sig') as f:
for line in f:
try:
key, value = line.split(' ', 1)
except:
key = line
# so this line must be '~EOR~\n'.
# All other lines must have the shape 'tag: content\n'
# so if this errors, there's something wrong with an input file
if not key.startswith('~EOR~'):
try:
record[key].append(value)
except KeyError:
record[key] = [value]
else:
reclist.append(record)
record = collections.OrderedDict()
return reclist
# put files into ordered dicts
source = recordlist(sourcefile)
target = recordlist(targetfile)
# patching
for fix in source:
for record in target:
if fix['ID'] == record['ID']:
record.update(fix)
# write-out
with codecs.open(resultfile, 'w', 'utf-8_sig') as f:
for record in target:
for tag, field in record.iteritems():
for occ in field:
line = u'{} {}'.format(tag, occ)
f.write(line)
f.write('~EOR~\n')
现在它是一个有序的dict。这不在我的OP中,但文件需要由人类交叉检查,所以保持秩序会更容易。(.我第一次尝试找到这个功能时,就想到了odict,但它的文档让我担心。没有例子,没有吓人的行话…)
此外,它现在支持记录中任意给定标记的多次出现。这也不在我的行动中,但我需要这个。(这种格式称为“Adlib标记”,是一种编目软件。)
与akaRem的方法不同的是修补,对目标dict使用update
。我发现这和python一样非常优雅。同样适用于启动时使用的。这是我忍不住分享的另外两个原因
我希望它有用 我会创建一个计数器“tPosition”,每次通过相关循环时都会增加它。然后,当您想说“t中的t线的其余部分”时,您可以表示您想循环如下内容:t中的t线[t位置:]谢谢!指向file.next()的链接具有我正在查找的确认信息。我已经看到了收益率的解释。跳过~EOR~
s是不好的。如果~EOR~
行后没有“ID”,则会损坏数据。在这种情况下,您需要提高
。在第行中,修复的只是损坏的的别名(这是相同的dict),因此您可以修改原始数据。这种代码风格在未来的开发中总是会带来bug。您需要断开的的深度副本。或者您必须重命名这些变量。另外,id
是内置的,您可以对其进行着色<代码>标记,val=[l.rstrip()表示行中的l.split(“”,1)]
将在删除数据的行上引发'T1'
->raiseThank your for your comments@akaRem。这是一个玩具示例,展示了OP可能不知道的一些Python语法和语义。我假设所有输入都是格式正确的,并且避免了错误检查。谢谢。我喜欢你处理记录的方法。我想它确实比我的更像蟒蛇。(我发现Pythonicness是一个相当困难的主题。里面有很多东西你可以使用,但你自己找不到)。您的代码在EOR行上崩溃,并带有“需要超过1个值才能解包”,我想curent
应该是current
,但这并不重要。这里不需要任何讨论。@RolfBly我是在PC上写的,没有安装python,所以。。我没有测试它。对不起,我犯了错误。我会修复它们。@RolfBly我已经添加了修复程序我花了一段时间才尝试你的代码。第一个记录[key]=value
导致TypeError:“NoneType”对象不支持项分配
。当然,输出文件仍然是空的。而且,第二个for循环不进行任何修补。