从文本文件中读取无分隔符的数值数组

2 投票
4 回答
3426 浏览
提问于 2025-04-16 18:27

我正在尝试从一个文本文件中读取一些数字数据,但遇到了一些困难,因为这些数字没有任何分隔符。这个文件的格式是一个在全球很多代码中都使用的标准格式,所以我们不能更改它。下面是一个示例文件的开头部分:

SOME TEXT OF A FIXED LENGTH      33
 3.192839854E+00 3.189751983E+00 3.186795271E+00 3.183874776E+00 3.180986976E+00
 3.178133610E+00 3.175318116E+00 3.172544681E+00 3.169818171E+00 3.167143271E+00
 3.164524875E+00 3.161968464E+00 3.159479193E+00 3.157062171E+00 3.154723040E+00
 3.152466964E+00 3.150299067E+00 3.148224863E+00 3.146249721E+00 3.144379226E+00
 3.142619004E+00 3.140974218E+00 3.139450283E+00 3.138052814E+00 3.136786929E+00
 3.135657986E+00 3.134671499E+00 3.133833067E+00 3.133149899E+00 3.132631559E+00
 3.132282773E+00 3.132080343E+00 3.131954939E+00
-5.487648393E-01-5.476736110E-01-5.447693831E-01-5.405765060E-01-5.353610408E-01
-5.291415409E-01-5.219573970E-01-5.137449740E-01-5.045337620E-01-4.943949468E-01
-4.832213992E-01-4.710109577E-01-4.578747780E-01-4.436967869E-01-4.285062978E-01
-4.123986122E-01-3.952894227E-01-3.771859951E-01-3.580934057E-01-3.379503384E-01
-3.168282028E-01-2.947799605E-01-2.716835737E-01-2.476267515E-01-2.226373818E-01
-1.966313850E-01-1.696421504E-01-1.415353640E-01-1.118510940E-01-8.041086734E-02
-4.968321601E-02-2.772555484E-02-2.631111359E-02
....

第一行包含一些注释(长度是固定的),后面跟着一个整数,这个整数表示后面数组的长度。数组本身是以固定宽度的数字列表存储的。在这个例子中,第一个数组应该不会给我带来问题。然而,从第二个数组可以看到,所有的数字都是负数,因此数字之间没有空格。所以,像 str.split() 这样的方法无法返回一个数字列表。我非常感谢任何关于如何处理这个文件的建议。

还有一个可能重要的信息:这些数组本身包含换行符,也就是说,以下代码

with open('some_file') as fh:
    data = [line for line in fh]

npts = int(data.pop(0).split()[-1])
print data

返回:

[' 3.192839854E+00 3.189751983E+00 3.186795271E+00 3.183874776E+00 3.180986976E+00\n',
 ' 3.178133610E+00 3.175318116E+00 3.172544681E+00 3.169818171E+00 3.167143271E+00\n',
 ' 3.164524875E+00 3.161968464E+00 3.159479193E+00 3.157062171E+00 3.154723040E+00\n',
 ' 3.152466964E+00 3.150299067E+00 3.148224863E+00 3.146249721E+00 3.144379226E+00\n',
 ' 3.142619004E+00 3.140974218E+00 3.139450283E+00 3.138052814E+00 3.136786929E+00\n',
 ' 3.135657986E+00 3.134671499E+00 3.133833067E+00 3.133149899E+00 3.132631559E+00\n',
 ' 3.132282773E+00 3.132080343E+00 3.131954939E+00\n', 
 '-5.487648393E-01-5.476736110E-01-5.447693831E-01-5.405765060E-01-5.353610408E-01\n',
 '-5.291415409E-01-5.219573970E-01-5.137449740E-01-5.045337620E-01-4.943949468E-01\n',
 '-4.832213992E-01-4.710109577E-01-4.578747780E-01-4.436967869E-01-4.285062978E-01\n',
 '-4.123986122E-01-3.952894227E-01-3.771859951E-01-3.580934057E-01-3.379503384E-01\n',
 '-3.168282028E-01-2.947799605E-01-2.716835737E-01-2.476267515E-01-2.226373818E-01\n',
 '-1.966313850E-01-1.696421504E-01-1.415353640E-01-1.118510940E-01-8.041086734E-02\n',
 '-4.968321601E-02-2.772555484E-02-2.631111359E-02\n', ... ]

希望这些信息比较清楚,如果你需要更多关于文件格式的信息,请告诉我。

4 个回答

0

这里有一些伪代码:

Loop though the line-as-string one character at a time. 
  |-> A. Add each character to a buffer. 
  |-> B. If you hit a space or hyphen character, treat either as a delimiter.
  |---> Add your buffered string to an array of numbers.
  |-> C. Reset buffer.
  |-> D. Repeat A. through C. until you hit a newline character.
1

Chris,在这种情况下,你应该使用 f.read(size) 来一个一个地读取数字。

这样可以让你有个大概念。另外,确保把原始的示例文件放到网上,这样我们才能用它来测试,因为直接复制粘贴到维基上可能会破坏格式。

def split_len(seq, length):
    return [seq[i:i+length] for i in range(0, len(seq), length)]

f = open("sample.txt")

header = f.readline()
(a,b,size) = header.rpartition(' ')
size = int(size)
lines = f.readlines()
found = 0
for line in lines:
    for number in split_len(line.rstrip(), 16):
        found = found + 1
        print(number)
        if found==size:
            break
3

这些数组本身是以固定宽度的数字列表形式存储的。

因为每个条目正好是十六个字符宽,所以下面的代码可以把你输入文件中的一行转换成一个浮点数的列表:

In [1]: line = '-5.487648393E-01-5.476736110E-01-5.447693831E-01-5.405765060E-01-5.353610408E-01'

In [2]: [float(line[i:i+16]) for i in xrange(0, len(line), 16)]
Out[2]: 
[-0.54876483929999997,
 -0.547673611,
 -0.5447693831,
 -0.54057650599999996,
 -0.53536104080000002]

在这里,我假设这一行没有结尾的换行符;如果可能有的话,可以使用str.rstrip先把它去掉。下面的代码片段还演示了如何把数字序列分成大小为n的小块(注意,它并没有尝试解析标题行):

n = 33
arr = []
for line in open('data.txt'):
  line = line.rstrip('\n')
  arr.extend(float(line[i:i+16]) for i in xrange(0, len(line), 16))
  if len(arr) >= n:
    print arr[:n]
    arr = arr[n:]

撰写回答