【问题标题】:csv.DictWriter returning blank strings if value is alphanumeric如果值为字母数字,则 csv.DictWriter 返回空白字符串
【发布时间】:2023-03-07 20:40:02
【问题描述】:

这是我的代码:

import csv
import os

for root, subFolders, files in os.walk('/path/to/folder/'):
    if 'routes.csv' in files:
        with open(os.path.join(root, "R.csv"), "r") as inf, \
                open(os.path.join(root, "B.csv"), "a") as output:
            reader = csv.DictReader(inf, quotechar='"')
            headers = ["R_id"]
            writer_B_routes = csv.DictWriter(output, headers, 
                                             extrasaction='ignore')
            writer_B_routes.writeheader()
            for row in reader:
                if int(row["R_type"]) == 3:
                    writer_B_routes.writerow(row)

当我在我的 CSV 文件夹上运行它时,如果 R_id 的值只是数字,那么它输出到 B.csv 很好(即1234)。但是,如果R_id 的值是字母数字(即A123),那么我在B.csv 中得到的输出是""

我尝试将int(row["R_type"]) == 3 更改为str(),认为方言的构建方式存在一些问题,但没有奏效。我不确定这些数据在哪里只传递了一个整数。

更新:链接到示例数据+脚本:Here

更新 2:我已经用其他几个样本进行了测试 - 案例似乎是独一无二的,但我无法确定原因。我有另一组包含R_id005M1 的样本数据,它运行正常。给我这个问题的数据有R_idE2 和类似的。但现在我知道它不适用于所有字母数字 ID。

【问题讨论】:

  • 你试过'if "3" in str(row["R_type")' 吗?
  • 这些字母数字 R_id 值是否在 CSV 文件中(更重要的是,在 row 字典中)?如果在 DictWriter 中使用 extrasaction='raise' 而不是 extrasaction='ignore',会发生什么?
  • @Jodgod 刚刚试过,同样的问题。 writer_B_routes.writerow(row) is supposed to write the value of R_id` - 如果它们是字母数字,它似乎会拒绝这些。我还尝试将quotechar='"' 添加到DictWriter,但没有运气。
  • 我会通过调试器运行它以查看 if 上发生了什么以及 row 的值是什么(或仅使用打印)。
  • 显然您在 routes.csv 的开头有一个特殊字符,它搞砸了列名。当我阅读您的文件时,第一列名称是 '\xef\xbb\xbfroute_id' 而不是 'route_id'。检查this post

标签: python csv


【解决方案1】:

请注意,以下内容指的是您在RemoveBAIO.py中的代码不是您的问题中显示的代码。

问题在于您尝试读取的routes.csv 文件是一个Unicode 文本文件,开头为UTF-8 Byte-Order-Mark(或BOM),而csv 正在获取该文件模块——它不能处理 Python 2 中的 Unicode 输入,在 @​​987654322@ 中注明——作为第一个字段的名称,所以它不是 "route_id",而是 "\xef\xbb\xbfroute_id"

这是您的代码稍作修改的版本,显示了处理可能具有初始 BOM 的文件的正确方法。它通过将codecs.open()'utf-8-sig'encoding 结合使用来实现这一点。此编码在codecsmodule 文档的Encodings and Unicode 部分中进行了描述。解码时,这将跳过任何存在的 BOM,而在编码时,它将首先写入 3 字节 BOM 序列。在下面的代码中,它故意仅用于读取输入文件(我解释了为什么进一步向下)。效果是输入文件中的第一个字段名称不会弄乱。

还请注意,我在'route_type'check 中删除了对int的转换,因此如果遇到包含非数字字符的异常,它不会引发ValueError异常。

bus_route_ids.csv没有有一个领先的 BOM。添加一个会很复杂,因为可能会将数据附加到其中,因此添加 BOM 必须以文件是否已经存在为条件。 FWIW,我还注意到 routes.csv 不是正确的 UTF-8,因为它在最后一行嵌入了一个 \xa0 字符,其序数值大于 128。

import codecs
import csv
import os

path_to_folder = '/insert/path/'

with open('hasfares.txt', 'w') as hf:
    for root, subFolders, files in os.walk(path_to_folder):
        if 'fare_rules.csv' in files:
            hf.write('%s\n' % root)

        if 'routes.csv' in files:
            routes_path = os.path.join(root, 'routes.csv')
            bus_route_ids_path = os.path.join(root, 'bus_route_ids.csv')
            appending_to_existing_file = os.path.exists(bus_route_ids_path)
            with codecs.open(routes_path, 'r', 'utf-8-sig') as inf, \
                    open(os.path.join(root, "bus_route_ids.csv"), "a") as output:
                reader = csv.DictReader(inf, quotechar='"')
                headers = ['route_id']
                writer_bus_routes = csv.DictWriter(output, headers,
                                                   extrasaction='ignore')
                if not appending_to_existing_file:
                    writer_bus_routes.writeheader()
                for row in reader:
                    if row['route_type'] == '3':
                        writer_bus_routes.writerow(row)

生成的bus_route_ids.csv 文件(假设它不存在):

route_id
E1
E2
N
N1
N2
N3
170
S1
S2
S3
S4
W1
W2
W3
W4
C

【讨论】:

  • @T.Mount:这不能回答你的问题吗?
  • 已继续使用上述 Paulo 的 cmets - 但您的解决方案更容易应用于我的数据集。再次感谢!
  • @T.Mount:我更新了我的答案,以显示处理 BOM 的正确方式,就像不是黑客一样——我最近在 SO 上了解到自己。新年快乐。
【解决方案2】:

试试

row["R_type"] == "3"

如果 R_type 是字母数字,那么它的类型是字符串。而 3 是一个 int。

Python 不会将 int 值 3 隐式解析为字符串,并且在字符串和 int 之间进行 == 比较将始终返回 false。要修复它,您将使用字符串版本“3”或将 3 转换为字符串 str(3)。

如果 R_type 可以从 CSV 解析为 int 或字符串,您还应该添加显式强制转换以始终强制转换为字符串,这样您就不会得到任何假阴性。

例如:

str(row["R_type"]) == "3"

【讨论】:

  • 我已经尝试了这两种情况,仍然返回 "" 作为 R_id
  • 如果没有数据样本,就不可能看出是什么破坏了它。
  • 上传到 Dropbox - 将在主要问题正文中发布一个链接。
猜你喜欢
  • 1970-01-01
  • 2021-11-30
  • 2023-01-26
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 2020-07-04
  • 2015-03-14
  • 1970-01-01
相关资源
最近更新 更多