我试图将用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。
你可以帮个忙吗?谢谢!答案 0 :(得分:0)
你得到了:
[' \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])
,您将获得该行的输出。
这里的问题是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