Python - 检查打开的文件

时间:2012-11-28 07:45:13

标签: python python-3.x

我有一个看起来像这样的文本文件:

BALLOTS CAST
Riding 0
YES YES NO YES
NO NO NO NO 
.
.
.
YES NO YES YES

Riding 1
YES NO NO YES
NO NO YES NO 
.
.
.
YES YES YES YES

等等。我有一个名为riding的骑乘号码的用户输入,然后我需要列出该骑行的投票。例如,如果骑行选择为0,那么我需要一个列表[[YES YES NO YES], [NO NO NO NO], ..., [YES NO YES YES]]

我需要找到一种方法来使用readline()while循环。这大致是我所拥有的:

ballots = open(FILENAME, 'r')
line = ballots.readline().rstrip()
L = []
i = 0
if riding.isdigit():
    while i < ???:
        line = ballots.readline().rstrip()
        i += 1
        if line == 'Riding ' + riding:
            while line != '\n':
                L.append(line.rstrip().split())

但我得到一个空列表。我也尝试使用180代替???,因为这是有多少行,但我不知道实际放在哪里。我尝试了max(enumerate(ballots))[0],但它完全清空了ballots列表(或者其他方式使所有内容都为空)。

任何人都可以指出我的错误以及我应该改变什么吗?正如我所说,我必须使用readline()while,我无法导入任何内容。

另外,我放if riding.isdigit()的原因是因为还有选择all选区的选项。它有效:

if riding == 'all':
    line = ballots.readline().rstrip()
    for line in ballots:
        if line[0:6] != 'Riding' and line != '\n':
            L.append(line.rstrip().split())

唯一的问题是我无法弄清楚如何使用while循环代替for循环......

3 个答案:

答案 0 :(得分:3)

看看Pickle:http://docs.python.org/2.7/library/pickle.html?highlight=pickle#pickle 它对于将python对象保存和恢复到文件非常有用,例如列表。

答案 1 :(得分:2)

您需要使用状态变量来检测何时应该读取行,并且当您完成break循环时:

lines = []
with open(FILENAME, 'r') as ballots:
    foundriding = False
    ballots.next()  # skip first line
    for line in ballots:
        if line.rstrip() == 'Riding ' + riding:
            foundriding = True
            continue
        if not foundriding: 
            continue
        line = line.rstrip()
        if line and not line.startswith('Riding '):
            lines.append(line)
        else:
            break

以上代码将跳过所有行,直到找到正确的Riding <number>行,此时它会将foundriding设置为True。设置标志后,它会将所有后续行添加到lines,直到找到空行或以Riding开头的行。那时它将打破阅读循环。

另一种方法是使用itertools.takewhile()

from itertools import takewhile
with open(FILENAME, 'r') as ballots:
    ballots.next()  # skip first line
    for line in takewhile(lambda l: l.rstrip() != 'Riding ' + riding, ballots):
        pass  # skip lines
    lines = [l.rstrip() for l in takewhile(lambda l: l.rstrip() and not l.startswith('Riding '), ballots)]

takewhile将从选票中取出线,直到测试返回False。在那之后,我们可以使用不同的测试来获取更多行,即该行不为空并且不以Riding开头。

两种解决方案都不需要读取整个文件。当我们找到正确的骑行时,我们就会停止阅读,所有的投票都被读入lines

我像迭代器一样使用ballots文件对象。这与.readline()的方法不完全相同;如果.readline()是一项艰难的要求(呃,教师和家庭作业),你也可以将ballot.readline()变成迭代器:

ballotiterator = iter(ballots.readline, '')

然后在ballotiteratorballotsfor line in ballots的任何地方使用ballots.next()代替takewhile(..., ballots)

答案 2 :(得分:1)

使用正则表达式的另一种解决方案:

import re
with open("test.txt") as infile:
    text = infile.read()
    if riding.isdigit():
        section = re.search(r"(?sm)^Riding " + riding + r".*?(?=Riding|\Z)", text)
        matches = re.findall(r"(?:(?:YES|NO) ?)+", section.group(0))
        result = [s.split() for s in matches]
        print(result)

riding设置为"1",结果为

[['YES', 'NO', 'NO', 'YES'], ['NO', 'NO', 'YES', 'NO'], ['YES', 'YES', 'YES', 'YES']]

当然,您可能想要使用

result = [[True if value == "YES" else False for value in s.split()] 
                                             for s in matches]

相反,为了得到

[[True, False, False, True], [False, False, True, False], [True, True, True, True]]

没有进行错误检查(例如,输入文件中是否存在标记为Riding x的段),但可以简单地添加。