我有一个看起来像这样的文本文件:
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
循环......
答案 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, '')
然后在ballotiterator
,ballots
或for 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
的段),但可以简单地添加。