读点直到点Python

时间:2013-04-11 23:25:46

标签: python text python-3.3 readlines

我有一个文本文件,其中包含以

开头的数据
#Name
#main

然后是大量的数字,然后文件以

结束
#extra
!side

所以这是一个小片段

#Name
#main
60258960
33031674
72302403
#extra
!side

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

所以我知道如何在标题

之后开始阅读
read=f.readlines()[3:]

但我对其他一切都很难过。有什么建议吗?

5 个答案:

答案 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将每个字符串值转换为整数也是微不足道的。

希望在决定使用何种方法执行手头的任务时,这会让您充分了解可能的情况以及所涉及的权衡。