我有一个包含以开头的数据的文本文件
#Name
#main
然后后面跟着很多数字,然后文件以
#extra
!side
所以这里有一个小片段
#Name
#main
60258960
33031674
72302403
#extra
!side
我只想阅读数字。但这是关键,我希望他们每个人都是他们自己的个人字符串。
所以我知道如何在标题之后阅读
read=f.readlines()[3:]
但我对其他一切都感到困惑。有什么建议么?
我有一个包含以开头的数据的文本文件
#Name
#main
然后后面跟着很多数字,然后文件以
#extra
!side
所以这里有一个小片段
#Name
#main
60258960
33031674
72302403
#extra
!side
我只想阅读数字。但这是关键,我希望他们每个人都是他们自己的个人字符串。
所以我知道如何在标题之后阅读
read=f.readlines()[3:]
但我对其他一切都感到困惑。有什么建议么?
逐行阅读。使用#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']
你很接近,就像你一样。您只需要修改列表切片以将文件中的最后两行连同前两行一起删除。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
我会做这样的事情:
nums = []
for line in f:
stripped = line.rstrip('\n')
if stripped.isnumeric():
nums.append(stripped)
nums
将仅包含那些带有数字的行。如果您的数字格式正确,则表示不是负数,也不是十六进制。这将需要一个正则表达式来精确匹配。
在没有参数的情况下使用它并不总是一个好主意(甚至可能是一个可行的主意),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)
通过使用而不是 just将每个字符串值转换为整数也很简单yield value
。
希望这能让您充分了解在决定使用哪种方法来执行手头任务时可能发生的事情以及所涉及的权衡取舍。
仅.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
值。如果你真的想要点作为字符串,你可以修改代码;我在那里留下评论以提醒您。