当记录标记的结尾不是新行时,我可以使用csv模块吗?

时间:2015-01-20 18:29:26

标签: python csv python-3.x

我想解析一个使用非ascii分隔符的类似csv的文件。 csv模块允许我设置引号字符和字段分隔符。是否可以设置记录分隔符的结尾,以便它可以与csv模块一起使用?

取一个类似csv的文件,而不是:

'"', ',', '\n'

它使用

'¦', '¶', '§'

例如

data = [
    [1,r'''text "could" be
'tricky'\\'''],
    [2,r'or easy']
]

将表示为

'1¶¦text "could" be\n\'tricky\'\\\\¦§2¶¦or easy¦'

我知道如何使用split等解决这个问题。但是csv模块有更好的方法吗?

此表达式生成示例:

chr(167).join(
[
        chr(182).join(
            [
                '\xa6{}\xa6'.format(val) if type(val)==str else str(val)
                for val in row
            ]
        ) for row in data
    ])

2 个答案:

答案 0 :(得分:3)

不,您不能直接使用csv.reader(),因为Dialect.lineterminator parameter是硬编码的:

  

注意reader是硬编码的,可以将'\r''\n'识别为行尾,并忽略lineterminator 。这种行为将来可能会改变。

您必须在阅读器周围创​​建一个包装器来翻译您的行终止符:

class LineTerminatorTranslator(object):
    def __init__(self, orig, terminator, buffer=2048):
        self._orig = orig
        self._terminator = terminator
        self._buffer = buffer

    def __iter__(self):
        terminator = self._terminator
        buffer = ''

        if hasattr(self._orig, 'read'):
            # read in chunks, rather than in lines, where possible
            iterator = iter(lambda: self._orig.read(self._buffer), '')
        else:
            iterator = iter(self._orig)

        while True:
            try:
                while terminator not in buffer:
                    buffer += next(iterator)
            except StopIteration:
                # done, yield remainder
                yield buffer
                return
            entries, _, buffer = buffer.rpartition(terminator)
            for entry in entries.split(terminator):
                yield entry

以2kb(可配置)的块读取输入文件,并按给定的行终止符拆分行。

因为csv.reader()可以处理任何迭代,所以代码也可以接受其他迭代,但是如果这样的迭代每次迭代都会生成大字符串,则效率会降低。

代码应该适用于Python 2和3。

演示:

>>> import csv
>>> import io
>>> sample = '1¶¦text "could" be\'tricky\n\'\\\\¦§2¶¦or easy¦'
>>> input = LineTerminatorTranslator(io.StringIO(sample), '§')
>>> list(csv.reader(input, delimiter='¶', quotechar='¦'))
[['1', 'text "could" be\'tricky\n\'\\\\'], ['2', 'or easy']]

有点人为的Python 2版本:

>>> import csv
>>> from cStringIO import StringIO
>>> sample = '1P|text "could" be\'tricky\n\'\\\\|T2P|or easy|'
>>> input = LineTerminatorTranslator(StringIO(sample), 'T')
>>> list(csv.reader(input, delimiter='P', quotechar='|'))
[['1', 'text "could" be\'tricky\n\'\\\\'], ['2', 'or easy']]

答案 1 :(得分:1)

您无法使用csv模块阅读此类文件。有一个名为lineterminator的选项,但documentation表示:

  

读者硬编码识别'\ r'或'\ n'作为行尾,并忽略lineterminator。这种行为将来可能会改变。

您显然可以使用此lineterminator参数编写此类文件,但您无法使用csv模块将其读回。