【问题标题】:csv reader in python3 with mult-character separators带有多字符分隔符的python中的csv阅读器
【发布时间】:2019-07-08 01:05:12
【问题描述】:

是否有替代使用csv 模块以流方式读取python3 中的csv 文件的替代方法?目前我的数据看起来像这样:

"field1"::"field2"::"field3"\x02\n
"1"::"hi\n"::"3"\x02\n
"8"::"ok"::"3"\x02\n

分隔符是两个字符,::csv 模块只接受一个字符分隔符)并且行分隔符也包含两个字符,\x02\n。是否有任何 csvreaders 可以在流模式下用于 python 并且能够支持这一点?

这是我正在尝试做的一个示例:

>>> import csv
>>> s = ''''"field1"::"field2"::"field3"\x02\n\n"1"::"hi\n"::"3"\x02\n\n"8"::"ok"::"3"\x02\n'''
>>> csvreader=csv.reader(s, delimiter='::', lineterminator='\x02\n')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: "delimiter" must be a 1-character string

加载 pandas 只是为了读取这个 csv 似乎有点矫枉过正 x 100,所以我想看看还有什么其他选择。

【问题讨论】:

  • 如果你能够控制这个 csv 的格式,我会切换到单个字符和不同的行分隔符,但我相信只使用 open 和 re 就足够了。
  • 你是说你想在同一个进程中用两个分隔符分隔数据吗?还有,你在用csv.reader吗?您能否发布您当前尝试用于清理此数据的代码部分?
  • 这是一个相关的 Q/A,但需要 pandas——对于这样一个小功能来说,这似乎是一个巨大的依赖:stackoverflow.com/questions/31194669/…
  • @BrianPeterson 同意——还有其他选择吗?
  • @Jaba re 变得非常棘手 - 使用转义字符、引号字符等。我宁愿不尝试也不这样做。

标签: python python-3.x csv


【解决方案1】:

正如您所发现的,CSV 库不适合该数据格式。您可以事先预先解析数据。例如,以下方法应该有效:

from io import StringIO
import csv

s = '''"field1"::"field2"::"field3"\x02\n\n"1"::"hi\n"::"3"\x02\n\n"8"::"ok"::"3"\x02\n'''

def csv_reader_alt(source):
    return csv.reader((line.replace('\x02', '').replace('::', ':') for line in source), delimiter=':')    

for row in csv_reader_alt(StringIO(s)):
    if row:
        print(row)

给你以下输出:

['field1', 'field2', 'field3']
['1', 'hi\n', '3']
['8', 'ok', '3']

【讨论】:

  • 感谢您。请参阅更新的问题,其中逐行读取行并不那么简单。
  • @DavidL 从你的小例子中很难说出确切的格式,但我现在已经展示了如何在将数据传递给普通的csv.reader() 之前预先解析数据。也许指向实际 CSV 文件的链接有助于测试。
【解决方案2】:

@MartinEvans 在他的回答中展示了一种很好的做法。

这是使用自定义分隔符(使用自定义生成器实现)通过适当的文件处理从文件(而不是内存中的字符串)读取的代码:

def get_line(file, delimiter='\n', bufsize=4096):
    # https://stackoverflow.com/a/19600562/9225671
    buf = ''
    while True:
        chunk = file.read(bufsize)
        if len(chunk) == 0:
            # end of file has been reached; serve the remaining data and exit
            yield buf
            return

        buf += chunk
        line_list = buf.split(delimiter)

        # don't serve the last part yet, first we need to read more chunks from the file
        buf = line_list.pop(-1)

        for line in line_list:
            yield line

if __name__ == '__main__':
    with open('my_file.csv') as f:
        for line in get_line(f, delimiter='\x02\n'):
            if len(line) > 0:
                parts = line.split('::')
                print(parts)
                print([
                    e.strip('"')
                    for e in parts])

这对你有用吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-31
    • 2018-03-03
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多