当前位置: 首页 > 面试题库 >

如何有效解析固定宽度的文件?

上官迪
2023-03-14
问题内容

我试图找到一种解析文件的方法,该文件包含固定宽度的线。例如,前20个字符代表一列,从21:30开始代表另一列,依此类推。

假设该行包含100个字符,将行解析为多个组件的有效方法是什么?

我可以每行使用字符串切片,但是如果行很大,这会有点难看。还有其他快速方法吗?


问题答案:

由于Python标准库的struct模块是用C编写的,因此使用它非常容易而且非常快捷。

这是可以用来完成您想要的事情的方法。通过为字段中的字符数指定负值,还可以跳过字符列。

import struct

fieldwidths = (2, -10, 24)  # negative widths represent ignored padding fields
fmtstring = ' '.join('{}{}'.format(abs(fw), 'x' if fw < 0 else 's')
                        for fw in fieldwidths)
fieldstruct = struct.Struct(fmtstring)
parse = fieldstruct.unpack_from
print('fmtstring: {!r}, recsize: {} chars'.format(fmtstring, fieldstruct.size))

line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n'
fields = parse(line)
print('fields: {}'.format(fields))

输出:

fmtstring: '2s 10x 24s', recsize: 36 chars
fields: ('AB', 'MNOPQRSTUVWXYZ0123456789')

以下修改将使其适应于Python 2或3(并处理Unicode输入):

import struct
import sys

fieldstruct = struct.Struct(fmtstring)
if sys.version_info[0] < 3:
    parse = fieldstruct.unpack_from
else:
    # converts unicode input to byte string and results back to unicode string
    unpack = fieldstruct.unpack_from
    parse = lambda line: tuple(s.decode() for s in unpack(line.encode()))

正如您所考虑的那样,这是一种处理字符串切片的方法,但担心它可能变得太丑陋。关于它的好处是,除了不那么丑陋之外,它还可以在Python
2和3中保持不变,并且能够处理Unicode字符串。在速度方面,它当然比基于struct模块的版本慢,但是可以通过删除具有填充字段的功能来稍微加快速度。

try:
    from itertools import izip_longest  # added in Py 2.6
except ImportError:
    from itertools import zip_longest as izip_longest  # name change in Py 3.x

try:
    from itertools import accumulate  # added in Py 3.2
except ImportError:
    def accumulate(iterable):
        'Return running totals (simplified version).'
        total = next(iterable)
        yield total
        for value in iterable:
            total += value
            yield total

def make_parser(fieldwidths):
    cuts = tuple(cut for cut in accumulate(abs(fw) for fw in fieldwidths))
    pads = tuple(fw < 0 for fw in fieldwidths) # bool values for padding fields
    flds = tuple(izip_longest(pads, (0,)+cuts, cuts))[:-1]  # ignore final one
    parse = lambda line: tuple(line[i:j] for pad, i, j in flds if not pad)
    # optional informational function attributes
    parse.size = sum(abs(fw) for fw in fieldwidths)
    parse.fmtstring = ' '.join('{}{}'.format(abs(fw), 'x' if fw < 0 else 's')
                                                for fw in fieldwidths)
    return parse

line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n'
fieldwidths = (2, -10, 24)  # negative widths represent ignored padding fields
parse = make_parser(fieldwidths)
fields = parse(line)
print('format: {!r}, rec size: {} chars'.format(parse.fmtstring, parse.size))
print('fields: {}'.format(fields))

输出:

format: '2s 10x 24s', rec size: 36 chars
fields: ('AB', 'MNOPQRSTUVWXYZ0123456789')


 类似资料:
  • 问题内容: 我从供应商那里得到了一个文件,每行有115个固定宽度的字段。如何将文件解析为115个字段,以便可以在代码中使用它们? 我首先想到的是只是为了让常数为每场像和使用。这看起来很丑,所以我很好奇这样做的更好方法。谷歌搜索打开的两个图书馆似乎都没有更好的选择。 问题答案: 我将使用像flatworm这样的平面文件解析器,而不是重新发明轮子:它具有简洁的API,易于使用,具有不错的错误处理能力和

  • 问题内容: 简单方案: 我需要为设置一个固定宽度。我试过了: 也 对于 乃至 但是的宽度仍然相同。 问题答案: 对于Bootstrap 4.0: 在Bootstrap4.0.0中,您不能可靠地使用这些类(在Firefox中有效,但在Chrome中不适用)。您需要使用OhadR的答案: 对于Bootstrap 3.0: 在twitter bootstrap 3中使用:其中*是宽度的列数。 对于Boo

  • 我试图使用统一解析器来解析一个固定宽度格式的文件,该文件每行包含可变数量的固定宽度记录。 格式为记录id[6],子记录[3]的#,子记录[6] 期望的结果是有一个子记录数组。@链接注释似乎适用,但留档声明这仅适用于超文本标记语言解析器。 我目前的解决方案是将子记录解析为字符串,然后循环遍历每个记录,并在子记录字符串中插入换行符,然后重新解析。有没有一种方法可以使用univocity解析器来实现这一

  • 问题内容: 我是Java Swing的新手,对下一个代码感到困惑。 我的目标是制作带有 2个JTextPane的 垂直可滚动面板 。具有父面板固定宽度70%的第一个JTextPane和具有固定宽度30%的第二个JTextPane。因为这两个JTextPane具有固定的宽度,所以它们只能在垂直方向上扩展更多文本。 我使用此解决方案,因为我只想为此2个JTextPane使用一个滚动条。 我的初始化代码

  • 我是Java Swing的新手,我对下一个代码感到困惑。 null

  • 问题内容: 在无序列表中: 允许添加class或style属性,但不允许填充文本以及添加或更改标签。 该页面正在使用Courier New呈现。 目标是在跨度后排列文本。 “ OR”的理由并不重要。 懒惰的动物文字可能包含在其他元素中,但我必须仔细检查。 问题答案: ul { 就像Eoin所说的那样,您需要在“空”跨度中放置一个不间断的空格,但是您不能为内联元素分配宽度,只能填充/边距,因此您需要