【问题标题】:Confronting "unacceptable character #x0095: special characters are not allowed in "<unicode string>", position 268" Error in Python yaml.load面对“不可接受的字符 #x0095:“<unicode string>”中不允许特殊字符,位置 268”Python yaml.load 中的错误
【发布时间】:2018-02-02 21:26:44
【问题描述】:

在将 YAML 格式传输到 Python 字典对象时,我遇到“不可接受的字符 #x0095:“”,位置 25 中不允许特殊字符”错误消息。
可能的解决方案是什么?

d = 'tended (Journaled)"\n  - "\x95 Support plug and play"\n'
a = yaml.load(d)

要传输的字符串是删节的,不是正确的 YAML 格式,但我想在这种情况下它是无关紧要的。 我正在使用 Python3

【问题讨论】:

  • Unicode 代码点十六进制 95 是一个 unicode 控制字符。见en.wikipedia.org/wiki/Unicode_control_characters——你想显示哪个字符?
  • 显示字符串不是我的目标。我正在尝试将凌乱的数据清理为可分析的 Python 格式...在执行 yaml.load() 之前我可以执行任何命令或编码以避免此错误消息?

标签: python yaml


【解决方案1】:

YAML specification 明确指出 YAML 流仅使用 Unicode 字符集的可打印子集。除了 NEL (\x85),C1 控制块中的字符是不允许的(即字符\x80-\x9F)。

这几乎是有效的 YAML:

d = 'tended (Journaled)"\n - " Support plug and play"\n'

你只需要在它前面有一个",在它后面加上一个:

d = '"tended (Journaled)":\n - " Support plug and play"\n'

(虽然我不确定 Journaled 的英文是否正确)

以下不是 YAML:

d = '"tended (Journaled)":\n  - "\x95 Support plug and play"\n'

因为\x95 在 C1 控制块中。您必须手动替换这些字符,或者删除它们。

ruamel.yaml 中没有太多可以帮助您转换此类非法字符的内容,但您可以使用Reader 的非法字符正则表达式来扫描非法字符并将其丢弃:

from ruamel.yaml import YAML
from ruamel.yaml.reader import Reader

yaml = YAML(typ='safe')


def strip_invalid(s):
    res = ''
    for x in s:
        if Reader.NON_PRINTABLE.match(x):
            # res += '\\x{:x}'.format(ord(x))
            continue
        res += x
    return res

d = '"tended (Journaled)":\n  - "\x95 Support plug and play"\n'

print(yaml.load(strip_invalid(d)))

给出:

{'tended (Journaled)': [' Support plug and play']}

无需任何进一步的人工干预。

如果您取消注释该行

        # res += '\\x{:x}'.format(ord(x))

你得到输出:

{'tended (Journaled)': ['\x95 Support plug and play']}

【讨论】:

    【解决方案2】:

    您必须检查凌乱的数据中是否存在无效字符。幸运的是,YAML 阅读器有一个产生必要数据的异常:

    import yaml
    
    try:
        d = 'tended (Journaled)"\n  - "\x95 Support plug and play"\n'
        a = yaml.load(d)
    except yaml.YAMLError as e:
        print("Parsing YAML string failed")
        print("Reason:", e.reason)
        print("At position: {0} with encoding {1}".format(e.position, e.encoding))
        print("Invalid char code:", e.character)
    

    如果您运行此代码,它会准确显示您的角色 \x95 是罪魁祸首。现在你必须更换/修复/询问用户,直到没有抛出异常。

    【讨论】:

    • 任何方法让代码运行但保持 \x95 不变?
    • e.position 是一个整数。如何在yaml文件中找到对应的行和放置?
    猜你喜欢
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多