3

我有一个包含以开头的数据的文本文件

#Name
#main

然后后面跟着很多数字,然后文件以

#extra
!side

所以这里有一个小片段

#Name
#main
60258960
33031674
72302403
#extra
!side

我只想阅读数字。但这是关键,我希望他们每个人都是他们自己的个人字符串。

所以我知道如何在标题之后阅读

read=f.readlines()[3:]

但我对其他一切都感到困惑。有什么建议么?

4

5 回答 5

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']

于 2013-04-11T23:31:36.330 回答
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
于 2013-04-11T23:31:43.807 回答
1

我会做这样的事情:

nums = []
for line in f:
  stripped = line.rstrip('\n')
  if stripped.isnumeric():
    nums.append(stripped)

nums将仅包含那些带有数字的行。如果您的数字格式正确,则表示不是负数,也不是十六进制。这将需要一个正则表达式来精确匹配。

于 2013-04-11T23:35:30.820 回答
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)通过使用而不是 just将每个字符串值转换为整数也很简单yield value

希望这能让您充分了解在决定使用哪种方法来执行手头任务时可能发生的事情以及所涉及的权衡取舍。

于 2015-01-13T00:02:08.297 回答
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值。如果你真的想要点作为字符串,你可以修改代码;我在那里留下评论以提醒您。

于 2013-04-29T23:50:30.920 回答