首页 > 解决方案 > 如何防止 csv 嗅探器认为连字符是 UNICODE 8722 而不是 45?

问题描述

我正在研究这个东西,它会尝试找出 csv 格式并询问最终用户是否正确。我开始使用时区进行测试,我的测试输入看起来像这样。

            "\r\n".join(
                (
                    "timestamp;col1;col2",
                    "2020-01-22T00:14:47-04:00;1;6.1",
                    "2020-02-23T01:15:47-04:00;2;7.1",
                    "2020-02-24T01:15:47-04:00;3;8.1",
                    "2020-02-25T01:15:47-04:00;4;9.1",
                    "2020-02-26T01:15:47-04:00;5;0.",
                )
            ).encode()

为了弄清楚方言我做

csv.Sniffer().sniff(lookup_row, self.allowed_delimiters)

我加载这个文件

csv.reader(opened_csv, dialect=dialect)

这是有趣的部分。当我将第一个时间戳复制粘贴parse到日期时间时

from dateutil import parser

a = '2020-01-22T00:14:47-04:00'
found_val = parser.parse(a)

它正确地返回日期时间。但是当我通过嗅探运行这个输入时,csv.reader 和迭代我的测试中的行dateutil无法解析它

b = '2020-01-22T00:14:47−04:00'  # <-- in my test case

a == b
>>> False

所以当我仔细看

a_ord = [ord(char) for char in a]  # [50, 48, 50, 48, 45, 48, 49, 45, 50, 50, 84, 48, 48, 58, 49, 52, 58, 52, 55, 45, 48, 52, 58, 48, 48]
b_ord = [ord(char) for char in b]  # [50, 48, 50, 48, 45, 48, 49, 45, 50, 50, 84, 48, 48, 58, 49, 52, 58, 52, 55, 8722, 48, 52, 58, 48, 48]

差异是-时区附近的标志。显然,“原始”复制粘贴会导致减号,即 UNICODE45sniffer认为(?)它是8722.

我大吃一惊,尤其是因为这个单元格中的其余连字符都被认为是45.

由于这是一个特殊情况,我只关心此列的正确解析,替换这个字符(如果找到)是最好的方法吗?

或者我可以以某种方式在嗅探器中定义错误的字符/限制 UNICODE 范围吗?

它应该被认为是一个错误dateutil吗?

标签: pythoncsv

解决方案


它应该被视为 dateutil 中的错误吗?

我不会这么说的。我对 dateutil 一无所知,但我想说您只是没有利用您可用的功能。

查看dateutil.parser.parse的文档,您似乎可以传递一个可选的dateutil.parser.parserinfo对象,该对象描述什么构成可接受的输入。

具体来说,我认为您需要查看dateutil.parser.parserinfo.JUMP,它似乎是可接受的分隔符列表,默认情况下如下所示:

JUMP= [' ', '.', ',', ';', '-', '/', "'", 'at', 'on', 'and', 'ad', 'm', 't', 'of', 'st', 'nd', 'rd', 'th']

所以,我猜,您所要做的就是通过包含您的特殊连字符parserinfo的自定义传入其中一个对象。JUMP


推荐阅读