如何忽略以UTF-8编码的Unicode空白字符?

时间:2017-12-11 21:05:42

标签: python python-2.7 csv utf-8 byte-order-mark

我有一个包含以下信息的csv文件:

id  name    age     height  weight
1   x       12      11      124
2   y       13      23      432
3   z       14      43      1435

它存储在名为Workbook2.csv的文件中 我使用以下代码:

ipFile = csv.DictReader(open('Workbook2.csv', 'rU'))
dict = {} # Tring to update the rows to this dictionary.
for row in ipFile:
    print row

我得到以下结果:

{'weight': '124', '\xef\xbb\xbfid': '1', 'height ': '11', 'age   ': '12', 'name ': 'x'}
{'weight': '432', '\xef\xbb\xbfid': '2', 'height ': '23', 'age   ': '13', 'name ': 'y'}
{'weight': '1435', '\xef\xbb\xbfid': '3', 'height ': '43', 'age   ': '14', 'name ': 'z'}

我想知道如何将此输出更新为字典。 我还想知道我如何忽略使用UTF-8编码的unicode字符,如果有一个过滤器我可以用来消除它们。

3 个答案:

答案 0 :(得分:2)

您的输入数据在每一行上都包含UTF-8 BOM sequences。无论是什么产生这个文件,似乎都是使用natsort()编解码器或非Python等价物一次一行追加数据。 BOM(如果使用的话)应该是文件中的第一个字符,而不在其他地方使用。如果你可以在源头解决这个问题,那么你的数据就会被破坏。

但是,有一种方法可以在阅读时修复此问题。 utf-8-sig模块读取的“文件”可以是在迭代时生成行的任何内容。使用生成器首先过滤文件行:

csv

然后将文件传递给过滤器,然后将其传递给from codecs import BOM_UTF8 def bom_filter(lines): for line in lines: if line.startswith(BOM_UTF8): line = line[len(BOM_UTF8):] yield line 对象:

DictReader()

演示:

with open('Workbook2.csv', 'rU') as inputfile:
    ipFile = csv.DictReader(bom_filter(inputfile))

在Python 3中,>>> from io import BytesIO >>> import csv >>> from codecs import BOM_UTF8 >>> def bom_filter(lines): ... for line in lines: ... if line.startswith(BOM_UTF8): ... line = line[len(BOM_UTF8):] ... yield line ... >>> demofile = BytesIO('''\ ... \xef\xbb\xbfid,name,age,height,weight ... \xef\xbb\xbf1,x,12,11,124 ... \xef\xbb\xbf2,y,13,23,432 ... \xef\xbb\xbf3,z,14,43,1435 ... ''') >>> ipFile = csv.DictReader(bom_filter(demofile)) >>> for row in ipFile: ... print row ... {'age': '12', 'height': '11', 'id': '1', 'weight': '124', 'name': 'x'} {'age': '13', 'height': '23', 'id': '2', 'weight': '432', 'name': 'y'} {'age': '14', 'height': '43', 'id': '3', 'weight': '1435', 'name': 'z'} 模块采用Unicode字符串输入(而不是字节串,所以现在需要查找解码结果,U + FEFF零宽度空间代码点。使代码工作在任何一个Python版本中,你必须在行的开头换掉你正在测试的内容:

csv

答案 1 :(得分:1)

有一个kwarg skipinitialspace但我从C代码验证它只查找''。

两种可能性:

  1. 子类DictReader添加一些代码以去掉空格
  2. 在将文件中的行传递到DictReader之前按下它们。
  3. (2)的一个例子是:

    def self.search(query)
        where(['phone ilike :query',
           'LOWER(name) ilike :query',
           'LOWER(email) ilike :query',
           'LOWER(address) ilike :query'].join(' OR '), {query: "%#{query}%" })
    end
    

答案 2 :(得分:0)

我认为输出明显被误解了。

DictReader从第一行获取字段名,第一列(在不可见BOM之后的那一列)只是“id”。这就是id字段现在每个记录都有前缀的原因。

在python 2.7和3.6中,我不得不使用方言csv.excel_tab来将标签解释为分隔符。

您的输入数据/ csv文件绝对可以,因为开头只有一个BOM(它应该在哪里)。您只需要在阅读之前剥离BOM。

E.g。像这样:

from codecs import BOM_UTF8
csv_file = open('test2.csv', 'rU')
csv_file.seek(len(BOM_UTF8))
ipFile = csv.DictReader(csv_file, dialect=csv.excel_tab)