【问题标题】:How to sniff csv line separators/terminators (csv.Sniffer() not working)如何嗅探 csv 行分隔符/终止符(csv.Sniffer() 不起作用)
【发布时间】:2019-05-18 07:29:39
【问题描述】:

我有以下数据,它使用\x01 作为字段分隔符,\x02\n 作为行分隔符。以下是数据示例:

#export_date\x01artist_id\x01name\x01is_actual_artist\x01view_url\x01artist_type_id\x02\n#primaryKey:artist_id\x02\n
#dbTypes:BIGINT\x01INTEGER\x01VARCHAR(1000)\x01BOOLEAN\x01VARCHAR(1000)\x01INTEGER\x02\n#exportMode:INCREMENTAL\x02\n
1475226000146\x011120695691\x01Kinitic SA\x011\x01http://itunes.apple.com/artist/kinitic-sa/id1120695691?uo=5\x017\x02\n

但是,当我尝试使用 csv 模块解析它时,我得到了以下结果:

with open('myfile', 'r') as csvfile:
    dialect = csv.Sniffer().sniff(csvfile.read(1024))
    print(dialect.__dict__)

mappingproxy({'module': 'csv', '_name': 'sniffed', 'lineterminator': '\r\n', 'quoting': 0, ' doc': None, 'doublequote': False, 'delimiter': ' ', 'quotechar': '"', 'skipinitialspace': False})

不幸的是,这是错误的,因为它认为分隔符是一个空格(即使我增加缓冲区大小也是错误的)。

有没有比使用那个模块更准确的方法来确定分隔符和行终止符?

【问题讨论】:

  • 嗅探器启发式可能不会扩展到那些奇怪的分隔符。检查源代码,默认为self.preferred = [',', '\t', ';', ' ', ':']
  • sniff 采用可选的delimiters 参数,一个包含所有可能分隔符的字符串。您是否尝试过,在您的情况下使用是否可行?
  • 如果你知道分隔符是什么,你为什么要嗅探文件?
  • @cody -- 我想。是否有类似所有可能分隔符的列表?不幸的是,我将它用于很多分隔符,我不确定哪些是实际合法的分隔符,哪些不是。
  • 使用您的数据,\x01 出现 15 次,但 t 出现 20 次。如果没有更多信息,我们如何知道它是哪个分隔符?您需要更多关于分隔符和行终止符的信息,否则无法回答

标签: python python-3.x csv


【解决方案1】:

这很 hackish,但是您可以计算输入流中的字符数以找出那些可能的分隔符。例如:

import collections

SEPARATORS=['\x00', '\x01', '\x02\n', '^', ':', ',', '\t', ':', ';', '|', '~']

def count_separator(filename, separators=SEPARATORS):
    with open(filename, 'r') as f:
        text = f.read(1024*1024)
    counts = collections.Counter(c for c in text if c in SEPARATORS)
    print (counts)
    return c.most_common()[0][0]

>>> count_separator('/Users/david/Desktop/validate_headers/artist')
Counter({'\x01': 48549, ':': 9752, '\x02': 9741, ',': 295, ';': 3})
'\x01'

上面的 badger0053 建议的另一个选项是仅将第一行数据用于嗅探器。这似乎效果更好:

SEPARATORS=['\x00', '\x01',  '^', ':', ',', '\t', ':', ';', '|', '~', ' ']
LINE_TERMINATORS_IN_ORDER = ['\x02\n', '\r\n', '\n', '\r']
with open('/Users/david/Desktop/validate_headers/artist', 'r') as csvfile:
    line = next(csvfile)
    dialect = csv.Sniffer().sniff(line, SEPARATORS)
    for _terminator in LINE_TERMINATORS_IN_ORDER:
        if line.endswith(_terminator):
            terminator = _terminator
            break
    print(repr(dialect.delimiter), repr(terminator))

'\x01' '\x02\n'

【讨论】:

  • @gboffi -- 谢谢,这比我正在做的更好吗?我敢肯定,我只是好奇,因为我(显然)以前没有用过那么多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 2017-03-20
  • 2014-10-21
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
相关资源
最近更新 更多