将utf16 csv转换为数组

时间:2014-08-02 16:32:57

标签: python csv utf-8 utf-16

我试图将用UTF-16编码的CSV文件(由另一个程序导出)转换为Python 2.7中的一个简单数组,但运气很少。

这是我找到的最近的解决方案:

from io import BytesIO
with open ('c:\\pfm\\bdh.txt','rb') as f:
    x = f.read().decode('UTF-16').encode('UTF-8')
        for line in csv.reader(BytesIO(x)):
            print line

此代码返回:

  

['tNombre \ tEtiqueta \ tExtensi \ xc3 \ xb3n de archivo \ tTama \ xc3 \ xb1ol \ xc3 \ xb3gico \ tCategor \ xc3 \ xada']   ['1 \ tnom1 \ tetq1 \ text1 ...

我想要的是这样的:

[['','Nombre','Etiqueta','Extensión de archivo','Tamaño lógico','Categoría']
 ['1','nom1','etq1','ext1','123','cat1']
 ['2','nom2','etq2','ext2','456','cat2']]

所以,我需要将这些十六进制字符转换为拉丁拼写错误(如:á,é,í,ó,ú或ñ),以及那些以制表符分隔的字符串转换为数组字段。

我真的需要在第一部分使用词典吗?我认为应该有一个更简单的解决方案,因为我可以通过键盘查看和编写所有这些字符。

对于第二部分,我认为CSV库在这种情况下无济于事,因为我读到它还无法管理UTF-16。

你可以帮个忙吗?谢谢!

2 个答案:

答案 0 :(得分:0)

项目#1:十六进制字符

你得到了:

[' \tNombre\tEtiqueta\tExtensi\xc3\xb3n de archivo\tTama\xc3\xb1ol\xc3\xb3gico\tCategor\xc3\xada']

输出,因为您正在打印list。列表的行为是打印每个项目的表示。也就是说,它相当于:

print('[{0}]'.format(','.join[repr(item) for item in lst]))

如果您使用print(line[0]),您将获得该行的输出。

项目#2:输出

这里的问题是csv解析器没有将内容解析为制表符分隔文件,而是以逗号分隔的文件。您可以使用以下方法解决此问题:

for line in csv.reader(BytesIO(s), delimiter='\t'):
    print(line)

代替。

这将为您提供所需的结果。

答案 1 :(得分:0)

在Python 2中使用csv模块处理UTF-16文件确实很麻烦。重新编码为UTF-8有效,但您仍然需要解码生成的列以生成unicode值。

另请注意,您的数据似乎是制表符分隔;默认情况下,csv.reader()使用逗号而不是制表符来分隔列。您需要将其配置为使用标签,方法是在构建阅读器时设置delimiter='\t'

使用io.open()读取UTF-16并生成unicode行。然后,您可以使用codecs.iterencode()将UTF-16文件中已解码的unicode值转换为UTF-8。

要将行解码回unicode值,您可以在迭代时使用额外的生成器来执行此操作:

import csv
import codecs
import io


def row_decode(reader, encoding='utf8'):
    for row in reader:
        yield [col.decode('utf8') for col in row]


with io.open('c:\\pfm\\bdh.txt', encoding='utf16') as f:
    wrapped = codecs.iterencode(f, 'utf8')
    reader = csv.reader(wrapped, delimiter='\t')
    for row in row_decode(reader):
        print row

每行仍然在每个包含的值上使用repr(),这意味着您将看到Python字符串文字语法来表示字符串。任何不可打印或非ASCII代码点都将由转义码代表:

>>> [u'', u'Nombre', u'Etiqueta', u'Extensión de archivo', u'Tamaño lógico', u'Categoría']
[u'', u'Nombre', u'Etiqueta', u'Extensi\xf3n de archivo', u'Tama\xf1o l\xf3gico', u'Categor\xeda']

这是正常;输出可用作调试辅助工具,可以粘贴回任何Python会话以重现原始值,而不必担心终端编码。

例如,ó表示为\xf3,表示Unicode代码点U+00F3 LATIN SMALL LETTER O WITH ACUTE。如果您要打印这一列,Python会将Unicode字符串编码为与您的终端编码匹配的字节,从而使您的终端再次显示正确的字符串:

>>> u'Extensi\xf3n de archivo'
u'Extensi\xf3n de archivo'
>>> print u'Extensi\xf3n de archivo'
Extensión de archivo

演示:

>>> import csv, codecs, io
>>> io.open('/tmp/demo.csv', 'w', encoding='utf16').write(u'''\
...  \tNombre\tEtiqueta\tExtensi\xf3n de archivo\tTama\xf1o l\xf3gico\tCategor\xeda
... ''')
63L
>>> def row_decode(reader, encoding='utf8'):
...     for row in reader:
...         yield [col.decode('utf8') for col in row]
... 
>>> with io.open('/tmp/demo.csv',  encoding='utf16') as f:
...     wrapped = codecs.iterencode(f, 'utf8')
...     reader = csv.reader(wrapped, delimiter='\t')
...     for row in row_decode(reader):
...         print row
... 
[u' ', u'Nombre', u'Etiqueta', u'Extensi\xf3n de archivo', u'Tama\xf1o l\xf3gico', u'Categor\xeda']
>>> # the row is displayed using repr() for each column; the values are correct:
... 
>>> print row[3], row[4], row[5]
Extensión de archivo Tamaño lógico Categoría