【问题标题】:How to read a file word by word如何逐字读取文件
【发布时间】:2014-10-16 04:16:11
【问题描述】:

我有一个 PPM 文件,我需要对其执行某些操作。该文件的结构如下例所示。第一行,“P3”只是说明它是什么类型的文件。在第二行中,它给出了图像的像素尺寸,所以在这种情况下,它告诉我们图像是 480x640。在第三行中,它声明了任何颜色可以采用的最大值。之后是代码行。每三个整数组给出一个像素的 rbg 值。所以在本例中,第一个像素的 rgb 值为 49、49、49。第二个像素的 rgb 值为 48、48、48,依此类推。

P3
480 640
255
49   49   49   48   48   48   47   47   47   46   46   46   45   45   45   42   42   42   38   38   
38   35   35   35   23   23   23   8   8   8   7   7   7   17   17   17   21   21   21   29   29   
29   41   41   41   47   47   47   49   49   49   42   42   42   33   33   33   24   24   24   18   18   
...

现在您可能会注意到,这个特定的图片应该是 640 像素宽,这意味着 640*3 整数将提供第一行像素。但是这里的第一行距离包含 640*3 个整数非常非常远。所以这个文件中的换行是没有意义的,所以我的问题。

读取 Python 文件的主要方式是逐行读取。但我需要将这些整数收集到 640*3 的组中,并将其视为一条线。如何做到这一点?我知道我可以逐行读取文件并将每一行附加到某个列表中,但是那个列表会很大,我认为这样做会给设备的内存带来不可接受的负担。但除此之外,我没有想法。帮助将不胜感激。

【问题讨论】:

标签: python python-2.7


【解决方案1】:

从文件中一次读取三个以空格分隔的单词:

with open(filename, 'rb') as file:
    kind, dimensions, max_color = map(next, [file]*3) # read 3 lines
    rgbs = zip(*[(int(word) for line in file for word in line.split())] * 3)

Output

[(49, 49, 49),
 (48, 48, 48),
 (47, 47, 47),
 (46, 46, 46),
 (45, 45, 45),
 (42, 42, 42),
 ...

What is the most “pythonic” way to iterate over a list in chunks?

为避免一次创建列表,您可以使用itertools.izip(),它允许一次读取一个 rgb 值。

【讨论】:

    【解决方案2】:

    可能不是最“pythonic”的方式,但是......

    遍历包含整数的行。

    保留四个计数 - 计数 3 - color_code_count,计数 1920 - numbers_processed,计数 - col (0-639) 和另一个 - rows (0-479)。

    对于遇到的每个整数,将其添加到索引为 list[color_code_count] 的临时列表中。增加 color_code_count、col 和 numbers_processed。

    一旦 color_code_count 为 3,您将获取临时列表并创建一个元组 3 或三元组(不确定术语是什么,但您的第一个像素的结构看起来像 (49,49,49)),并将其添加到640 列和 480 行的列表 - 将 (49, 49, 49) 插入像素[col][row]。

    增量列。 重置 color_code_count。
    'numbers_processed' 将继续递增,直到达到 1920。

    当您到达 1920 年时,您已到达第一行的末尾。
    将 numbers_processed 和 col 重置为零,将 row 递增 1。

    此时,您应该在零行中有 640 个元组 3 或三元组,以 (49,49,49)、(48、48、48)、(47、47、47) 等开头。现在开始在第 1 行第 0 列中插入像素值。

    就像我说的,可能不是最“pythonic”的方式。使用 join 和 map 可能有更好的方法,但我认为这可能有效吗?如果您想这样称呼这个“解决方案”,则不应该关心任何行上的整数数量,因为您在开始新行之前一直在计算您希望通过多少个数字(1920)。

    【讨论】:

    • 是的,我可能会实现这样的东西,谢谢!
    【解决方案3】:

    遍历每个单词的一种可能方法是遍历每一行,然后将 .split 遍历到每个单词中。

    the_file = open("file.txt",r)
    
    for line in the_file:
        for word in line.split():
            #-----Your Code-----     
    

    从那里你可以用你的“词”做任何你想做的事。您可以添加if-statements 以检查每行中是否有数字:(虽然不是很pythonic)

    for line in the_file:
        if "1" not in line or "2" not in line ...:
            for word in line.split():
                #-----Your Code-----
    

    或者您可以测试每行是否有任何内容:(更多pythonic)

    for line in the_file:
        for word in line.split():
            if len(word) != 0 or word != "\n":
                #-----Your Code-----    
    

    我建议将每个新“行”添加到新文档中。

    【讨论】:

      【解决方案4】:

      我是C 程序员。抱歉,如果这段代码看起来像 C Style:

      f = open("pixel.ppm", "r")
      type = f.readline()
      height, width = f.readline().split()
      height, width = int(height), int(width)
      max_color = int(f.readline());
      colors = []
      count = 0
      col_count = 0
      line = []
      while(col_count < height):
          count = 0
          i = 0
          row =[]
          while(count < width * 3):
              temp = f.readline().strip()
              if(temp == ""):
                  col_count = height
                  break
              temp = temp.split()
              line.extend(temp)
              i = 0
              while(i + 2 < len(line)):
                  row.append({'r':int(line[i]),'g':int(line[i+1]),'b':int(line[i+2])})
                  i = i+3
                  count = count +3
                  if(count >= width *3):
                      break
              if(i < len(line)):
                  line = line[i:len(line)]
              else:
                  line = []
          col_count += 1
          colors.append(row)
      for row in colors:
          for rgb in row:
              print(rgb)
          print("\n")
      

      您可以根据自己的需要进行调整。我在这个文件上测试过:

      P4
      3 4
      256
      4 5 6 4 7 3
      2 7 9 4
      2 4
      6 8 0 
      3 4 5 6 7 8 9 0 
      2 3 5 6 7 9 2 
      2 4 5 7 2 
      2
      

      【讨论】:

        【解决方案5】:

        这似乎可以解决问题:

        from re import findall
        
        def _split_list(lst, i):
            return lst[:i], lst[i:]
        
        def iter_ppm_rows(path):
            with open(path) as f:
                ftype = f.readline().strip()
                h, w = (int(s) for s in f.readline().split(' '))
                maxcolor = int(f.readline())
        
                rlen = w * 3
                row = []
                next_row = []
        
                for line in f:
                    line_ints = [int(i) for i in findall('\d+\s+', line)]
        
                    if not row:
                        row, next_row = _split_list(line_ints, rlen)
                    else:
                        rest_of_row, next_row = _split_list(line_ints, rlen - len(row))
                        row += rest_of_row
        
                    if len(row) == rlen:
                        yield row
                        row = next_row
                        next_row = []
        

        它不是很漂亮,但它允许文件中数字之间的不同空格以及不同的行长。

        我在一个如下所示的文件上对其进行了测试:

        P3
        120 160
        255
        0   1   2   3   4   5   6   7   
        8   9   10   11   12   13   
        14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   33   34   
        [...]
        9993   9994   9995   9996   9997   9998   9999   
        

        该文件使用随机行长度,但按顺序打印数字,因此很容易判断行开始和停止的值。请注意,它的尺寸与问题的示例文件中的不同。

        使用下面的测试代码...

        for row in iter_ppm_rows('mock_ppm.txt'): 
            print(len(row), row[0], row[-1])
        

        ...结果如下,似乎没有跳过任何数据并返回正确大小的行。

        480 0 479
        480 480 959
        480 960 1439
        480 1440 1919
        480 1920 2399
        480 2400 2879
        480 2880 3359
        480 3360 3839
        480 3840 4319
        480 4320 4799
        480 4800 5279
        480 5280 5759
        480 5760 6239
        480 6240 6719
        480 6720 7199
        480 7200 7679
        480 7680 8159
        480 8160 8639
        480 8640 9119
        480 9120 9599
        

        可以看出,文件末尾不能代表完整行的尾随数据没有产生,这是意料之中的,但您可能希望以某种方式对其进行解释。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-10
          • 1970-01-01
          • 2011-11-02
          • 1970-01-01
          相关资源
          最近更新 更多