我有一个文本文件,其中包含以
开头的数据#Name
#main
然后是大量的数字,然后文件以
结束#extra
!side
所以这是一个小片段
#Name
#main
60258960
33031674
72302403
#extra
!side
我想只读数字。但这是踢,我希望他们每个人都是他们自己的个人字符串。
所以我知道如何在标题
之后开始阅读read=f.readlines()[3:]
但我对其他一切都很难过。有什么建议吗?
答案 0 :(得分:4)
逐行阅读。使用#main作为标志开始处理。使用#extra作为标志来停止处理。
start = '#main'
end = '#extra'
numbers = []
file_handler = open('read_up_to_a_point.txt')
started = False
for line in file_handler:
if end in line:
started = False
if started:
numbers.append(line.strip())
if start in line:
started = True
file_handler.close()
print numbers
示例输出
python read_up_to_a_point.py ['60258960','33031674','72302403']
答案 1 :(得分:3)
你很亲密,就像你一样。您只需要修改列表切片以切断文件中的最后两行以及前两行。 readlines
自然会返回一个列表,其中每个项目都是文件中的一行。但是,它也会在每个字符串的末尾加上“换行符”字符,因此您可能需要对其进行过滤。
with open("myfile.txt") as myfile:
# Get only numbers
read = myfile.readlines()[2:-2]
# Remove newlines
read = [number.strip() for number in read]
print read
答案 2 :(得分:1)
我会做这样的事情:
nums = []
for line in f:
stripped = line.rstrip('\n')
if stripped.isnumeric():
nums.append(stripped)
nums
将仅包含带数字的那些行。如果你的数字形成良好,意味着不是负数,也不是十六进制数。这将采用正则表达式来精确匹配。
答案 3 :(得分:1)
如果您知道输入文件可以很好地适应内存,那么您应该只使用.readlines()
;它一次读取所有行。
大多数情况下,您可以一次读取一个输入行,为此可以只迭代文件句柄对象。
当你想要特殊的,棘手的输入处理时,我建议将处理封装在这样的生成器函数中:
def do_something_with_point(point):
print(point)
class BadInputFile(ValueError):
pass
def read_points_data(f):
try:
line = next(f)
if not line.startswith("#Name"):
raise BadInputFile("file does not start with #Name")
line = next(f)
if not line.startswith("#main"):
raise BadInputFile("second line does not start with #main")
except StopIteration:
raise BadInputFile("truncated input file")
# use enumerate() to count input lines; start at line number 3
# since we just handled two lines of header
for line_num, line in enumerate(f, 3):
if line.startswith("#extra"):
break
else:
try:
yield int(line)
except ValueError:
raise BadInputFile("illegal line %d: %s" % (line_num, line))
# if you really do want strings: yield line
else:
# this code will run if we never see a "#extra" line
# if break is executed, this doesn't run.
raise BadInputFile("#extra not seen")
try:
line = next(f)
if not line.startswith("!side"):
raise BadInputFile("!side not seen after #extra")
except StopIteration:
raise BadInputFile("input file truncated after #extra")
with open("points_input_file.txt") as f:
for point in read_points_data(f):
do_something_with_point(point)
请注意,此输入函数会彻底验证输入,并在输入中出现任何错误时引发异常。但是使用输入数据的循环简单而干净;使用read_points_data()
的代码可以整洁。
我让read_points_data()
将输入点转换为int
值。如果你真的想要点作为字符串,你可以修改代码;我在那里留下了一个评论提醒你。
答案 4 :(得分:1)
在没有参数的情况下使用readlines()
并不总是一个好主意(或者甚至是可行的),因为它会在整个文件中读取并可能消耗大量内存 - 并且这样做如果你根本不需要所有这些,可能没有必要,具体取决于你正在做什么。
因此,实现您想要的一种方法是使用Python 生成器函数从文件中仅提取所需的行或值。它们非常容易创建,基本上您只需使用yield
语句来返回值而不是return
。从编程的角度来看,它们之间的主要区别在于,下次调用函数时,执行将继续执行yield
语句之后的行,而不是通常情况下的第一行。这意味着它们的内部状态会在后续调用之间自动保存,这使得在其中进行复杂处理变得更加容易。
这里是一个相当小的例子,它使用一个从文件中获取您想要的数据,逐步增加一行,因此它不需要足够的内存来保存整个档案:
def read_data(filename):
with open(filename, 'rt') as file:
next(file); next(file) # ignore first two lines
value = next(file).rstrip('\n') # read what should be the first number
while value != '#extra': # not end-of-numbers marker
yield value
value = next(file).rstrip('\n')
for number in read_data('mydatafile'):
# process each number string produced
当然,如果您愿意,您仍然可以将它们全部收集到一个列表中,如下所示:
numbers = list(read_data('mydatafile'))
正如您所看到的,可以在函数中执行其他有用的操作,例如验证文件数据的格式或以其他方式预处理它。在上面的示例中,我通过删除它返回的列表的每一行上的换行符readlines()
叶来完成一些操作。使用yield int(value)
而不是yield value
将每个字符串值转换为整数也是微不足道的。
希望在决定使用何种方法执行手头的任务时,这会让您充分了解可能的情况以及所涉及的权衡。