如果value是字母数字,则csv.DictWriter返回空字符串

时间:2013-12-16 23:55:57

标签: python csv

这是我的代码:

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(),认为Dialect的构建方式存在一些问题,但这不起作用。我不确定这个数据只传递一个整数。

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

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

2 个答案:

答案 0 :(得分:3)

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

问题是您尝试读取的routes.csv文件是一个Unicode文本文件,其开头是UTF-8 Byte-Order-Mark(或BOM),正在被提取csv模块 - 它无法处理Python 2中的Unicode输入,在documentation中注明 - 作为第一个字段的名称,因此它不是"route_id"它的"\xef\xbb\xbfroute_id"

以下是代码的略微修改版本,显示了处理可能初始BOM的文件的正确方法。它通过将codecs.open()'utf-8-sig'编码结合使用来实现此目的。此编码在codecs模块的文档的Encodings and Unicode部分中进行了描述。解码时,将跳过任何存在的BOM和编码,它将首先写入3字节的BOM序列。在下面的代码中,它故意仅用于读取输入文件(我解释了为什么进一步下来)。结果是输入文件中的第一个字段名称没有搞砸。

另请注意,我已将int检查中的转化移至'route_type',因此如果遇到包含非数字字符的异常,则不会引发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

答案 1 :(得分:0)

尝试

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"