使用Python从文本文件导入数据

4 投票
5 回答
5445 浏览
提问于 2025-04-15 23:47

我有一个文本文件,里面的数据是按行和列排列的,总共有大约17000行。每一列的字符长度都是固定的,没用的字符用空格填充。例如,第一列的长度是11个字符,但最后四个字符总是空格(这样在文本编辑器里看起来就像整齐的列)。如果某个条目少于7个字符,空格可能会多于四个。

这些列之间没有用逗号、制表符或空格分开。而且每列的字符数也不全相同,前两列是11个字符,接下来的两列是8个字符,最后一列是5个字符——不过同样,有些地方是空格。

我想做的是,如果第二列中包含字符串'OW',就把最后两列的数字导入进来。任何帮助都非常感谢。

5 个回答

0

这里有一个可能对你有帮助的函数:

def rows(f, columnSizes):
    while True:
        row = {}
        for (key, size) in columnSizes:
            value = f.read(size)
            if len(value) < size: # EOF
                return
            row[key] = value
        yield row

下面是一个使用这个函数的例子:

from StringIO import StringIO

sample = StringIO("""aaabbbccc
d  e  f  
g  h  i  
""")

for row in rows(sample, [('first', 3),
                         ('second', 3),
                         ('third', 4)]):
    print repr(row)

需要注意的是,这个例子和其他答案不同,它不是按行分隔的(它只是把文件当作字节的来源,而不是行的迭代器)。因为你特别提到字段没有分隔,所以我假设行也可能没有分隔;换行符是特别考虑的。

你可以用'in'操作符来检查一个字符串是否是另一个字符串的一部分。例如:

>>> 'OW' in 'hello'
False
>>> 'OW' in 'helOWlo'
True

所以在这种情况下,你可以这样做:

if 'OW' in row['third']:
    stuff()

当然,你可以根据需要测试任何字段的任何值。

3

在Python中,你可以通过切片来提取已知位置的子字符串,通常用的语法是list[start:end]。不过,你也可以创建切片对象,这样可以在之后的代码中使用它们来进行索引。

所以你可以这样做:

columns = [slice(11,22), slice(30,38), slice(38,44)]

myfile = open('some/file/path')
for line in myfile:
    fields = [line[column].strip() for column in columns]
    if "OW" in fields[0]:
        value1 = int(fields[1])
        value12 = int(fields[2]) 
        ....

把切片分开放到一个列表里,如果数据格式改变了,或者你需要处理其他字段时,这样做会让修改代码变得简单。

4

Python中的struct.unpack可能是分割固定长度字段最快的方法。这里有一个函数,它会懒惰地读取你的文件,并返回符合你条件的数字元组:

import struct

def parsefile(filename):
    with open(filename) as myfile:
        for line in myfile:
            line = line.rstrip('\n')
            fields = struct.unpack('11s11s8s8s5s', line)
            if 'OW' in fields[1]:
                yield (int(fields[3]), int(fields[4]))

使用方法:

if __name__ == '__main__':
    for field in parsefile('file.txt'):
        print field

测试数据:

1234567890a1234567890a123456781234567812345
something  maybe OW d 111111118888888855555
aaaaa      bbbbb      1234    1212121233333
other thinganother OW 121212  6666666644444

输出结果:

(88888888, 55555)
(66666666, 44444)

撰写回答