编写/解析固定宽度行的文本文件

14 投票
8 回答
35004 浏览
提问于 2025-04-15 11:31

我刚开始学习Python,想用它来写一些我们供应商需要的复杂EDI内容。

简单来说,他们需要一个80个字符宽的固定格式文本文件,里面有些字段是有数据的,有些则是空白的。我手里有文档,所以我知道每个字段的长度。收到的回复更容易处理,因为里面已经有数据,我可以用Python的“切片”功能来提取我需要的部分,但我不能直接给切片赋值——我试过了,因为这听起来是个好办法,但没成功,因为Python的字符串是不可变的 :)

正如我所说,我真的很新手,但我对学习Python感到兴奋 :) 我该怎么做呢?理想情况下,我希望能说第10到20个字符等于“Foo”,并且它是字符串“Foo”后面加上7个空格(假设这个字段的长度是10),然后把它放进更大的80个字符的字段里,但我不太确定怎么实现我想的这个。

8 个回答

7

你可以使用 对齐 函数来把一个字符串靠左对齐、靠右对齐或者居中对齐,适应指定的宽度。

'hi'.ljust(10) -> 'hi        '
10

希望我理解你的意思:你想要一种简单的方法来方便地识别每一部分内容,并用一个简单的变量表示,同时输出时要对齐到正确的宽度,对吧?

下面的代码片段可能能满足你的需求:

class FixWidthFieldLine(object):

    fields = (('foo', 10),
              ('bar', 30),
              ('ooga', 30),
              ('booga', 10))

    def __init__(self):
        self.foo = ''
        self.bar = ''
        self.ooga = ''
        self.booga = ''

    def __str__(self):
        return ''.join([getattr(self, field_name).ljust(width) 
                        for field_name, width in self.fields])

f = FixWidthFieldLine()
f.foo = 'hi'
f.bar = 'joe'
f.ooga = 'howya'
f.booga = 'doin?'

print f

运行后会得到:

hi        joe                           howya                         doing     

这个方法是通过存储一个类级别的变量 fields 来实现的,它记录了每个字段在输出中应该出现的顺序,以及每个字段应该占用的列数。同时,在 __init__ 方法中有相应命名的实例变量,最开始设置为空字符串。

__str__ 方法会把这些值输出为一个字符串。它使用了一个列表推导式,遍历类级别的 fields 属性,通过名称查找每个字段的实例值,然后根据列数将输出左对齐。最后,得到的字段列表会用一个空字符串连接在一起。

需要注意的是,这个方法并不会解析输入,不过你可以很容易地重写构造函数,让它接受一个字符串,并根据 fields 中的字段和字段宽度来解析列。它也不会检查实例值是否超过了分配的宽度。

22

你不需要给切片赋值,只需要用 % 格式化 来构建字符串。

下面是一个固定格式的例子,包含3个数据项:

>>> fmt="%4s%10s%10s"
>>> fmt % (1,"ONE",2)
'   1       ONE         2'
>>> 

同样的,数据中提供了字段宽度:

>>> fmt2 = "%*s%*s%*s"
>>> fmt2 % (4,1, 10,"ONE", 10,2)
'   1       ONE         2'
>>> 

分开数据和字段宽度,并使用 zip()str.join() 的技巧:

>>> widths=(4,10,10)
>>> items=(1,"ONE",2)
>>> "".join("%*s" % i for i in zip(widths, items))
'   1       ONE         2'
>>> 

撰写回答