Comment forcer PyYAML à des chaînes de charge comme des objets unicode?
-
04-10-2019 - |
Question
Les charges de paquet PyYAML chaînes non marquées comme des objets soit unicode ou str, en fonction de leur contenu.
Je voudrais utiliser des objets unicode tout au long de mon programme (et, malheureusement, ne peut pas passer à Python 3 pour l'instant).
Yat-il un moyen facile de forcer PyYAML à toujours les objets de unicode de charge? Je ne veux pas encombrer mon YAML avec des balises !!python/unicode
.
# Encoding: UTF-8
import yaml
menu= u"""---
- spam
- eggs
- bacon
- crème brûlée
- spam
"""
print yaml.load(menu)
Sortie: ['spam', 'eggs', 'bacon', u'cr\xe8me br\xfbl\xe9e', 'spam']
Je voudrais: [u'spam', u'eggs', u'bacon', u'cr\xe8me br\xfbl\xe9e', u'spam']
La solution
Voici une version qui remplace la manipulation PyYAML des chaînes en produisant toujours unicode
. En réalité, ce qui est probablement le résultat identique de l'autre réponse que j'ai posté sauf plus court (à savoir vous encore devez vous assurer que les chaînes dans les classes personnalisées sont converties en unicode
ou passés vous chaînes de unicode
si vous utilisez des gestionnaires personnalisés):
# -*- 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
""")
(Le ci-dessus donne [u'spam', u'eggs', u'bacon', u'cr\xe8me br\xfbl\xe9e', u'spam']
)
Je ne l'ai pas testé sur LibYAML
(l'analyseur à base c) que je ne pouvais pas le compiler, donc je vais laisser l'autre réponse qu'il était.
Autres conseils
Voici une fonction que vous pouvez utiliser à utiliser pour remplacer str
avec les types de unicode
de la sortie décodée de 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]})