我在 Python 中打开文件时出错,错误是UnicodeEncodeError
.
该程序打开并处理yaml
在 Windows 中创建的文件,但我不知道它是用什么编码创建的。在 Ubuntu 16.10 和 macOS Sierra 上都会出现此问题。
具体错误是:
Traceback (most recent call last):
File "metas.py", line 75, in <module>
for meta in metas:
File "/usr/local/opt/pyenv/versions/metas/lib/python2.7/site-packages/yaml/__init__.py", line 80, in load_all
loader = Loader(stream)
File "/usr/local/opt/pyenv/versions/metas/lib/python2.7/site-packages/yaml/loader.py", line 34, in __init__
Reader.__init__(self, stream)
File "/usr/local/opt/pyenv/versions/metas/lib/python2.7/site-packages/yaml/reader.py", line 79, in __init__
self.determine_encoding()
File "/usr/local/opt/pyenv/versions/metas/lib/python2.7/site-packages/yaml/reader.py", line 135, in determine_encoding
self.update(1)
File "/usr/local/opt/pyenv/versions/metas/lib/python2.7/site-packages/yaml/reader.py", line 165, in update
exc.encoding, exc.reason)
yaml.reader.ReaderError: 'utf8' codec can't decode byte #xf3: invalid continuation byte
in "<string>", position 273
该文件metas.py
或多或少是这样的:
# coding: utf-8
import yaml
from imp import reload
MIEMBRO = 'JMM'
VERSION = 1.0
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
IMPORTS = """# -*- coding: UTF-8 -*-
from django.conf import settings
from django.db import models
from core.models import Pipol, PUESTOS
from django.contrib.contenttypes.models import ContentType
from django import forms
from metas.models import Evidencia
from metas.models import subir_archivo
from metas.forms import FormEvidenciaBase
from django.contrib.auth import get_user_model
User = get_user_model()
"""
class Generador:
def __init__(self, meta):
self.miembro = meta['miembro']
self.id = meta['id']
self.nombre = meta['nombre']
self.repeticiones = meta['repeticiones']
self.campos = meta['campos']
def get_campos(self):
return self.campos
def get_meta(self):
return '%s%02d' % (self.miembro.upper(), self.id)
def get_model(self):
clase = """class %s(Evidencia):""" % self.get_meta()
for c in self.get_campos():
for k, v in c.iteritems():
blank = u'blank=True, null=True' if v[1] else ''
clase += u"\n %s = models.FileField('%s', \
upload_to=subir_archivo, %s)" % (k, v[0], blank)
clase += u"""\n
class Meta:
app_label = 'metas'
"""
return clase
def get_form(self):
clase = """class Formulario%s(FormEvidenciaBase):
class Meta:
model = %s\n\n""" % (self.get_meta(), self.get_meta())
return clase
if __name__ == '__main__':
file = '%s.yml' % MIEMBRO.lower()
metas = yaml.load_all(open(file).read())
print IMPORTS
for meta in metas:
m = Generador(meta)
print(m.get_model())
print(m.get_form())
该文件yaml
是这样的:
miembro: vol
id: 1
nombre: u'3 propuestas OE'
repeticiones: 1
campos:
- correo: ['Correo Electrónico', false]
- oficio: ['Oficio de cumplimiento', false]
- propuestas: ['Propuestas', false]
---
miembro: vol
id: 2
nombre: u'Modelo operativo recepción paquetes'
repeticiones: 1
campos:
- correo: ['Correo Electrónico', false]
- oficio: ['Oficio de cumplimiento', false]
- modelo_operativo: ['modelo operativo', false]
- acuse_entrega: ['acuse', false]
- observaciones: ['observaciones', true]
字符#xf3
对应于ó
.
最后,我的团队的前提如下:
(metas) javier@toledano:Projects/metas_sdk ‹master*›$ locale
LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL=
版
当我cat archivo.yml
在控制台中执行此操作时,它是这样的:
miembro: VRL
id: 1
nombre: Entrega CECyRD
repeticiones: 12
campos:
- acta: ['Acta', false]
- oficio_acta: ['Oficio Acta', false]
- oficio_entrega: ['Oficio Entrega', false]
- correo: ['Correo', false]
- estad▒stico: ['Estad▒stico', false]
@ixi 关于 using 的评论
with open(filename, encoding="latin-1")
是 Python 3.x 的正确方法。由于您使用的是 Python 2.x,这是不可能的,因为内置函数open
不接受encoding
Python 2.x 中的参数:与 Python 3.x 不同:
会有几种可能性,但我认为最简单的方法是以二进制打开它并使用正确的编码(ISO 8859-1 或 Latin-1)对其进行解码:
创建一个名为
archivo.yml
低编码的文件Latin-1
并使用您提供的内容,我得到以下输出:我认为这是正确的,虽然说实话我从来没有开车
PyYaml
。该代码适用于 Windows 10 和 Kubuntu 16.10 以及 Python 2.7。MACOS 原则上没有 Ubuntu 应该没有问题...编辑: 正如我在下面的评论中提到的,另一个解决方案是制作文件的副本,但使用 UTF-8 编码。它可以用 python 完成,或者因为我们在 Ubuntu 系统上,我们可以使用终端进行复制。位于我们拥有文件的目录中:
这为我们创建了一个使用 UTF-8
archivo.yml
调用的 (Latin-1)的副本archivo2.yml
,我们可以直接在 Python 脚本中使用它。我们甚至可以使用subprocess
.