【问题标题】:Error in looping through a text file in python在python中循环一个文本文件时出错
【发布时间】:2017-06-17 17:40:56
【问题描述】:

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

--- 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)

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

【问题讨论】:

  • 试着写成两个连续的循环,而不是嵌套它们。 Loop1:跳过所有行直到--- section1...。 Loop2:转储所有行,直到遇到另一个 ---
  • 鉴于过去类似标题的经验,我预计这是一个需要关闭的垃圾问题。相反,找到了一个措辞明确的问题,基本上所有相关信息都存在。许多荣誉OP。
  • 忽略我原来的(现已删除)评论。很久没有看到elsewhile 循环了。
  • break 不应该在else 中。内部with 肯定不应该在while 循环中。
  • 请不要直接编辑问题中的代码。

标签: python file loops while-loop


【解决方案1】:

看起来你把事情复杂化了。我想内部while 循环内的next 会绊倒外部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 发生冲突。

如果您想写入更多文件,基本上,在循环中添加更多状态并将 write sn-p 移回循环内。我不想特别解释这如何等同于状态机,但应该不难理解:有两个状态,你是跳过或收集;为了扩展这一点,在返回时为边界添加一个状态,您可以在其中写出收集的数据并将收集的行重新初始化为无。

【讨论】:

  • 外部for 循环不是导致问题的原因。问题中明确说明了这一点。
  • 此外,您的代码还将添加所有不在 section1 中的行。
  • 嗯?当您到达第 2 部分时,elif 会跳到末尾。
  • OP 尝试中内循环中的 next 操纵外循环的 file 迭代器。
  • 我同意下一个是个坏主意。事实是它们中有两个把事情搞砸了,而不是它在一个 for 循环中。
【解决方案2】:

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)

【讨论】:

  • 给定输入文件,当停止条件是包含--- 的行时,您并没有真正解释如何可能到达文件末尾。
  • 另外,写入需要在循环之外。
  • @MadPhysicist 确实如此。谢谢。
  • 另外,与@tripleee 的分析器相同的问题。它不适用于除第一个部分之外的任何部分。我敢打赌 OP 也希望将此代码重用于其他部分。
【解决方案3】:

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

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

  1. 当您已经在 for 循环中时,在生成器(如文件)上使用 next 可能会导致未定义的行为。这次你可能会侥幸逃脱,但一般来说这不是一个好习惯。顺便说一句,您侥幸逃脱的主要原因可能是,一旦触发了while,您就永远不会真正将控制权返回给for 循环,而不是文件在这方面特别宽松。
  2. 将数据转储到文件的内部with 位于while 循环内。这意味着您使用'w' 权限打开的文件将在while 的每次迭代中被截断(即文件中的每一行)。随着数组的增长,输出实际上会很好,但您可能希望将其移出内部循环。

最简单的解决方案是在两个循环中重写代码:一个找到您关心的部分的开头,另一个处理它直到找到结尾。

类似这样的:

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 出现在其他带有破折号的行之后,您绝对需要这种双循环方法。其他答案中的单循环解决方案在不平凡的情况下不起作用。

【讨论】:

  • 虽然使用正则表达式可以提供更好的精确度来准确匹配您想要的模式,但在这种情况下,它看起来像一个复杂的启动项。
  • @tripleee。我不同意你的看法。我确实注意到,如果您查找 section1 以外的部分,或者如果 section1 不是第一部分,则双循环解决方案是必要的。
猜你喜欢
  • 2020-05-30
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
相关资源
最近更新 更多