2013-04-11 29 views
3

我有一个文本文件的完整数据与阅读,直到一个点的Python

#Name 
#main 

然后启动它,然后许多数字,然后将该文件与

#extra 
!side 

所以这里有一个结束小片段

#Name 
#main 
60258960 
33031674 
72302403 
#extra 
!side 

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

所以我知道如何读头后开始

read=f.readlines()[3:] 

但我难倒一切。有什么建议么?

回答

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 
+1

你可以用'read = myfile.read()。splitlines()[2:-2]'几乎同时去掉换行符。 – martineau

+0

请注意'.strip()'也会去掉任何前导/尾部空格或制表符。你可以使用'number.rstrip(“\ n”)'来避免这种情况。 (这与OP的问题无关,但可能对读者有用) – bfontaine

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 

样本输出

蟒蛇read_up_to_a_point.py [ '60258960', '33031674', '72302403']

1

我会做这样的事情:

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

nums只包含那些数字的那些行。如果你的数字是正确的,意味着不是负数,而不是十六进制。这将需要一个正则表达式来精确匹配。

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值。如果你真的想要点作为字符串,你可以修改代码;我在那里留言,提醒你。

+0

认真?看起来像是寻找问题的解决方案......而这个问题中的问题不在于此。 – martineau

+0

@martineau我认为这是一个很好的答案。也许提问者可能不会检查输入,但我认为验证输入数据并没有错,而且这个答案显示了如何在自己的函数中隐藏所有的验证。注意使用数据的'for'循环是干净整洁的,尽管检查非常彻底......发生器是我喜欢Python的东西之一。 – steveha

+0

如果解决OP的问题,那么将输入文件的读取封装在生成器函数中的想法可能具有一些优点。但恕我直言,你的示例代码会更好,如果它只是说明了核心概念。我并不是说输入验证和错误处理并不重要,但这个问题与他们无关。你可以指出,你的技术可以帮助他们做到这一点,而不必在其所有的荣耀中这样做。在答案的代码中很难[参见树木的森林](http://en.wiktionary.org/wiki/see_the_forest_for_the_trees#Verb)。 – martineau

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

希望这会给你足够的想法,以确定什么是可能的,以及在决定使用什么方法来执行手头任务时所涉及的折衷。

+0

由于您正在文本模式下打开文件,因此您应该使用'\ n'来表示行结束。你可能想使用“通用换行”模式:https://docs.python.org/2/library/functions.html?highlight=open#open由于'file'是一个内置关键字,我通常不会使用'file'作为标识符。但那些是尼特;我喜欢答案。 – steveha

+0

@ steveha:谢谢 - 毕竟,只是你自己的想法有一点不同。你说得对,只需要''\ n'',但是在'rU''模式下打开文件并不是因为在'文本模式'下打开文件 - 'r''和''rt ''都这么做 - 意味着将启用平台相关的换行符处理。这意味着无论是否在所使用的Python解释器中启用了通用换行符支持,它们都将转换为单一字符“\ n”,只是它将由操作系统处理(可能会更快)。 – martineau