在python中循环遍历文本文件时出错

时间:2017-02-01 04:30:30

标签: python file loops while-loop

我正在尝试循环文本文件并应用一些逻辑,但我无法遍历文本文件。所以目前我有一个文本文件,结构如下:

--- section1 ---
"a","b","c"
"d","e","f"
--- section2 ---
"1","2","3"
"4","5","6"
--- section3 ---
"12","12","12"
"11","11","11"

我试图过滤出包含'---'的第一行,并将下面的行转换为json,直到下一行'---'行出现在文本文档中。

但是我收到此错误“ fields1 = next(file).split(',')StopIteration

with open(fileName,'r') as file:
    for line in file:
        if line.startswith('-') and 'section1' in line:
            while '---' not in next(file):
                fields1 = next(file).split(',')
                for x in range(0,len(fields1)):
                    testarr.append({
                    config.get('test','test'): fields1[x]           
                    })

                with open(test_dir,'w') as test_file:
                    json.dump(testarr, test_file)

知道为什么我的代码不起作用或我如何解决错误?

3 个答案:

答案 0 :(得分:2)

看起来你大量过分复杂。我想象的内部next循环中的while正在绊倒外部for循环,但这无论如何都是不必要的。你已经在线上循环了;选择你想要的,然后在你完成后退出。

with open(fileName,'r') as inputfile:
    for line in inputfile:
        if line.startswith('-') and 'section1' in line:
            continue
        elif line.startswith('-'):
            break
        else:
            testarr.append({config.get('test', 'test'): x
                for x in line.split(',')})

with open(test_dir,'w') as test_file:
    json.dump(testarr, test_file)

我希望我得到append权利,因为我还想向您展示如何更优雅地映射分割字段,但我不确定我是否完全理解您的原始代码所做的事情。 (我猜你实际上想要在分割之前修剪掉\n行。然后,我想你想要修剪每个值周围的引号。x.strip('"') for x in line.rstrip('\n').split(',')

我还将file重命名为inputfile,以避免与保留关键字file发生冲突。

如果要编写更多文件,基本上,在循环中添加更多状态,并将写代码段移回循环内部。我不是特别想解释它是如何等同于状态机的,但它应该不难理解:有两个状态,你正在跳过或收集;为了扩展这一点,在翻转时为边界添加一个状态,在此处写出收集的数据并将收集的行重新初始化为无。

答案 1 :(得分:2)

您的错误的原因是您滥用文件对象生成器时通过调用next两次,就像您想象的那样频繁。每次调用next都会获得一行并将其返回。因此,while '---' not in next(file): fields1 = next(file).split(',')获取一行,检查---,然后获取另一行并尝试解析它。这意味着您可以跳过包含---的行,使其出现在第二个next中。在这种情况下,您将在找到要查找的行之前到达文件的末尾。 StopIteration是迭代器通常表明其输入已用尽的方式。

您可能希望在代码中解决其他一些问题:

  1. 当您已经在next循环内时,在文件生成器上使用for可能会导致未定义的行为。这次你可能会侥幸成功,但这并不是一般的好习惯。顺便说一下,你逃避它的主要原因可能是,一旦for被触发,你永远不会真正将控制权返回到while循环,而且这方面的文件并不是特别宽容
  2. 将数据转储到文件的内部with位于while循环内。这意味着您使用'w'权限打开的文件将在while的每次迭代(即文件中的每一行)中被截断。随着数组的增长,输出实际上看起来很好,但你可能想要将它移出内循环。
  3. 最简单的解决方案是在两个循环中重写代码:一个用于查找您关注的部分的开头,另一个用于处理它直到找到结束。

    这样的事情:

    test_arr = []
    with open(fileName, 'r') as file:
        for line in file:
            if line.startswith('---') and 'section1' in line:
                break
    
        for line in file:
            if '---' in line:
                break
            fields1 = line.split(',')
            for item in fields1:
                testarr.append({config.get('test','test'): item})
    
    with open(test_dir,'w') as test_file:
        json.dump(testarr, test_file)
    

    编辑:

    考虑到@ tripleee的建议,我已经删除了起始行的正则表达式检查。虽然正则表达式为查找特定模式提供了极高的精度和灵活性,但对于这个例子来说这实在是太过分了。我想指出,如果你正在寻找除section1之外的部分,或者如果section1出现在带有破折号的其他行之后,那么你绝对需要这种双循环方法。其他答案中的单循环解决方案不适用于非平凡的情况。

答案 2 :(得分:0)

当迭代器用尽时,

next()会引发StopIteration异常。换句话说,你的代码到达文件的末尾,然后再次调用next(),并且没有更多内容可以返回,因此它会引发异常。

至于如何解决问题,我想这可能是你想要的:

with open(fileName, 'r') as file:
    for line in file:
        if line.startswith('---'):
            if 'section1' in line:
                continue
            else:
                break
        fields1 = line.split(',')
        for x in range(len(fields1)):
            testarr.append({
                config.get('test', 'test'): fields1[x]
            })

with open(test_dir, 'w') as test_file:
    json.dump(testarr, test_file)