Cómo forzar PyYAML a las cadenas de carga como objetos Unicode?
-
04-10-2019 - |
Pregunta
Las cargas de paquetes PyYAML cadenas sin marcar como Unicode o str objetos, en función de su contenido.
Me gustaría utilizar objetos Unicode a través de mi programa (y, por desgracia, no se puede cambiar a Python 3 por el momento).
¿Hay una manera fácil de forzar a PyYAML siempre cadenas objetos Unicode carga? No quiero que el desorden de mi YAML con etiquetas !!python/unicode
.
# Encoding: UTF-8
import yaml
menu= u"""---
- spam
- eggs
- bacon
- crème brûlée
- spam
"""
print yaml.load(menu)
Salida: ['spam', 'eggs', 'bacon', u'cr\xe8me br\xfbl\xe9e', 'spam']
Me gustaría: [u'spam', u'eggs', u'bacon', u'cr\xe8me br\xfbl\xe9e', u'spam']
Solución
Aquí hay una versión que anula el manejo de cadenas por PyYAML siempre unicode
salida. En realidad, este es probablemente el resultado idéntico de la otra respuesta que he publicado, excepto más corto (es decir, que todavía tienen que asegurarse de que las cadenas en clases personalizadas se convierten en unicode
o se pasan cadenas unicode
a sí mismo si utiliza controladores personalizados):
# -*- coding: utf-8 -*-
import yaml
from yaml import Loader, SafeLoader
def construct_yaml_str(self, node):
# Override the default string handling function
# to always return unicode objects
return self.construct_scalar(node)
Loader.add_constructor(u'tag:yaml.org,2002:str', construct_yaml_str)
SafeLoader.add_constructor(u'tag:yaml.org,2002:str', construct_yaml_str)
print yaml.load(u"""---
- spam
- eggs
- bacon
- crème brûlée
- spam
""")
(Lo anterior da [u'spam', u'eggs', u'bacon', u'cr\xe8me br\xfbl\xe9e', u'spam']
)
No he probado en LibYAML
(el analizador basado en c) ya que no podía compilarlo sin embargo, así que voy a dejar la otra respuesta como estaba.
Otros consejos
Esta es una función que podría utilizar para usar para reemplazar str
con tipos unicode
desde la salida decodificada del PyYAML
:
def make_str_unicode(obj):
t = type(obj)
if t in (list, tuple):
if t == tuple:
# Convert to a list if a tuple to
# allow assigning to when copying
is_tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
obj[x] = make_str_unicode(obj[x])
if is_tuple:
# Convert back into a tuple again
obj = tuple(obj)
elif t == dict:
for k in obj:
if type(k) == str:
# Make dict keys unicode
k = unicode(k)
obj[k] = make_str_unicode(obj[k])
elif t == str:
# Convert strings to unicode objects
obj = unicode(obj)
return obj
print make_str_unicode({'blah': ['the', 'quick', u'brown', 124]})