【问题标题】:Insert blanks into output file pointer (ofp)将空格插入输出文件指针 (ofp)
【发布时间】:2025-12-16 18:00:01
【问题描述】:

这个脚本的目的是获取一个传入的 csv 文件,用 DictReader 读取它, 获取读取的键,查看它们是否匹配 fieldMap 字典中的任何预先指定的值,如果匹配,则将这些键附加到我的 hdrlist。然后,将头列表写入输出文件调用ofp。

我遇到的这个问题是,当我没有与 fieldMap 中预先指定的值之一匹配的键时,我需要插入一个空白('')。

我已经尝试在 else 语句中将空白值附加到 hdrlist 并在我的 fieldMap 字典中有一个空白键值对:

if row.has_key(ft_test):
    hdrlist.append(ft_test)
else:
    hdrlist.append('')


'':[''] #blank key:value pair

,然后是我的:

if hdrlen != len(hdrlist)-1:
    print "Cannot Cannot find a key for %s in file %s" % (ft,fn)"

错误处理语句返回的打印语句比我认为的要多,我不确定为什么。

如果有人能阐明如何在我的 ofp.write(fmtstring) 中插入空白,将不胜感激。

另外,如果有人能解释为什么我得到的打印语句比我认为我应该使用上述 else 语句得到更多的打印语句,我将不胜感激。

我的整个脚本如下,如果需要任何其他信息来帮助我编写此代码,我会很乐意提供。

这里是一个输入文件的示例,它会产生许多打印语句。

input_file.csv = {'cust_no':1, 'streetaddr':'2103 Union Ave','address2':' ','city':'Chicago'}

#!/usr/bin/env python
import sys, csv, glob

fieldMap = {'zipcode':['Zip5', 'zip9','zipcode','ZIP','zip_code','zip','ZIPCODE'],
        'firstname':['firstname','FIRSTNAME'],
        'lastname':['lastname','LASTNAME'],
        'cust_no':['cust_no','CUST_NO'],
        'user_name':['user_name','USER_NAME'],
        'status':['status','STATUS'],
        'cancel_date':['cancel_date','CANCEL_DATE'],
        'reject_date':['REJECT_DATE','reject_date'],
        'streetaddr':['streetaddr','STREETADDR','ADDRESS','address'],
        'streetno':['streetno','STREETNO'],
        'streetnm':['streetnm','STREETNM'],
        'suffix':['suffix','SUFFIX'], #suffix of street name: dr, ave, st
        'city':['city','CITY'],
        'state':['state','STATE'],
        'phone_home':['phone_home','PHONE_HOME'],
        'email':['email','EMAIL'],
        '':['']
        }


def readFile(fn,ofp):
    count = 0
    CSVreader = csv.DictReader(open(fn,'rb'), dialect='excel', delimiter=',')
    for row in CSVreader:
        count+= 1
        if count == 1:
            hdrlist = []
            for ft in fieldMap.keys():
                hdrlen = len(hdrlist)
                for ft_test in fieldMap[ft]:
                    if row.has_key(ft_test):
                        hdrlist.append(ft_test)
                if hdrlen != len(hdrlist)-1:
                    print "Cannot find a key for %s in file %s" % (ft,fn)


        if len(hdrlist) != 16:
            print "Another error. Not all header's have been assigned new values."
        if count < 5:
            x=len(hdrlist)
            fmtstring = "%s\t" * len(hdrlist) % tuple(row[x] for x in hdrlist)
            ofp.write(fmtstring)
            break

if __name__ == '__main__':

    filenames = glob.glob(sys.argv[1])
    ofp = sys.stdout
    ofp.write("zipcode\tfirstname\tlastname\tcust_no\tuser_name\tstatus\t"
              "cancel_date\treject_date\tstreetaddr\tstreetno\tstreetnm\t"
              "suffix\tcity\tstate\tphone_home\temail")

    for filename in filenames:
        readFile(filename,ofp)

样本数据:

cust_no,status,streetaddr,address2,city,state,zipcode,billaddr,servaddr,title,latitude,longitude,custsize,telemarket,dirmail,nocredhold,email,phone_home,phone_work,phone_fax,phone_page,phone_cell,phone_othr,taxrate1,taxrate2,taxrate3,taxtot,company,firstname,lastname,user_name,dpbc,container,seq,paytype_am,paytype_di,paytype_mc,paytype_vi
0,0,'123 fake st.',,'chicago','il',60185,'123 billaddr st.','123 servaddr st.','mr.',43.123,54.234 ,2000,'TRUE','TRUE','TRUE','email@email.com',(666)555-6666,,,,,,,,,,,'bob','smith','bob smith',,,,'TRUE','TRUE','TRUE','TRUE'
0,0,'123 fake st.','','chicago','il',60185,'123 billaddr st.','123 servaddr st.','mr.',43.123,54.234 ,2000,'TRUE','TRUE','TRUE','email@email.com',(666)555-6666,'','','','','','','','','','','bob','smith','bob smith','','','','TRUE','TRUE','TRUE','TRUE'

【问题讨论】:

  • 您能否提供至少一个产生过多打印语句的输入文件?
  • 您添加的内容与您的for row in CSVreader: 循环中的row 的值类似。我的意思是文件中的一行或多行实际数据。您可以稍微更改一下以保护隐私。还包括在 csv 文件中定义字段名称的第一行会很有用。
  • 很难让它像表格一样格式化,但我的列标题是:邮政编码,名字,姓氏,cust_no,用户名,状态,cancel_date,reject_date,streetaddr,streetno,streetnm,后缀,城市,状态,电话家庭,电子邮件。在每个列标题下方是多行适当类型的数据。
  • 你不能从 csv 文件中复制一两个问题行并将它们粘贴到你的问题中吗?我想要一些真实的数据来测试。顺便说一句,列标题决定了csv.DictReader 可能在每行字典中返回的键,因此对每一行执行所有冗余检查似乎效率低下(且复杂)。
  • 如果我复制所有行,则无法将其格式化为表格,但我复制了 5 列,其中包含虚假数据。

标签: python if-statement dictionary


【解决方案1】:

如果您想要的只是正在处理的 csv 文件中已识别字段名称的 hdrlist,您可以在创建 @ 后立即通过将 DictReader.fieldnames 属性中的值与 fieldMap 的内容进行比较来创建它987654324@ 因为使用filenames 参数这样做会自动读取文件的标题行。

我还将您的 fieldMap 字典更改为 OrderedDict,以便保留键的顺序。

import glob
from collections import OrderedDict
import csv
import sys

fieldMap = OrderedDict([
    ('zipcode', ['zipcode', 'ZIPCODE', 'Zip5', 'zip9', 'ZIP', 'zip_code', 'zip']),
    ('firstname', ['firstname', 'FIRSTNAME']),
    ('lastname', ['lastname', 'LASTNAME']),
    ('cust_no', ['cust_no', 'CUST_NO']),
    ('user_name', ['user_name', 'USER_NAME']),
    ('status', ['status', 'STATUS']),
    ('cancel_date', ['cancel_date', 'CANCEL_DATE']),
    ('reject_date', ['reject_date', 'REJECT_DATE']),
    ('streetaddr', ['streetaddr', 'STREETADDR', 'ADDRESS', 'address']),
    ('streetno', ['streetno', 'STREETNO']),
    ('streetnm', ['streetnm', 'STREETNM']),
    ('suffix', ['suffix', 'SUFFIX']),  # suffix of street name: dr, ave, st
    ('city', ['city', 'CITY']),
    ('state', ['state', 'STATE']),
    ('phone_home', ['phone_home',' PHONE_HOME']),
    ('email', ['email', 'EMAIL']),
])

def readFile(fn,ofp):
    with open(fn, 'rb') as csvfile:
        # the following reads the header line into csvReader.fieldnames
        csvReader = csv.DictReader(csvfile, dialect='excel', delimiter=',')
        # create a list of recognized fieldnames in the csv file
        hdrlist = []
        for ft in fieldMap:
            for ft_test in fieldMap[ft]:
                if ft_test in csvReader.fieldnames:
                    hdrlist.append(ft_test)
                    break
            else:
                hdrlist.append(None)  # placeholder (could  also be '')
        hdrlen = len(hdrlist)
        ofp.write('hdrlist: {}\n'.format(hdrlist))
        if hdrlen != len(fieldMap):
            print "Note that not all field names were present in file."

        ofp.write("\t".join(fieldMap) + '\n')
        for row in csvReader:
            fmtstring = "%s\t" * hdrlen % tuple(
                row[field] if field else 'NA' for field in hdrlist)
            ofp.write(fmtstring+'\n')

if __name__ == '__main__':
#    sys.argv = [sys.argv[0], 'ofp_input.csv']  # hardcode for testing
    if len(sys.argv) != 2:
        print "Error:  Filename argument missing!"
        sys.exit(-1)
    filenames = glob.glob(sys.argv[1])
    ofp = sys.stdout
    for filename in filenames:
        readFile(filename, ofp)

【讨论】:

  • 不用担心。我明白。我更改了 CSV 数据。我很抱歉之前把它变成了一张桌子。我应该在数据之间加上逗号。我的错。对不起。数据现在以逗号分隔,中间没有空格。
  • 现在的数据看起来像 csv 文件中的那种数据吗?如果没有,我可以改变它。
  • 是的,这看起来更真实......我现在应该能够改进我的答案......等等。
  • 看我现在已经没有时间做进一步的工作了,但我保证我会这样做并发布更新。
  • 您的样本数据似乎仍然不一致。第一行,标题,定义了 38 个逗号分隔的字段名,但下一行数据只包含 25 个逗号分隔的数据项。它们的顺序也不正确。例如,在标题中,第七项应该是zipcode,但下一行中该位置的数据值是'123 billaddr st.',看起来它可能应该是billaddr,这是标题行中的第八项。再次,请提供一些真实的输入数据。