如何强制 Python 中的 plistlib 保存转义的特殊字符?

How to force plistlib in Python to save escaped special characters?

我的 plistlib 模块有点问题。它工作正常,除了保存 plists 时。它不会将撇号保存为特殊字符。它确实将 & 保存为 &,这很好,但是将撇号保存为 '(而不是 '),这并不好。我有很多包含大量文本的 plist,当我更改某些内容(使用脚本进行批量更改)时,git diff 让我很头疼,因为每个 ' 都会变成 '

如何强制plistlib保存所有特殊字符转义的plist(毕竟只有5个)?

我会回答我自己的问题,因为我四处寻找并找到了答案。

模块 plistlib 中的函数 _escape(text) 有问题。它仅转义 &<>,尽管 Xcode 及其 plist reader 转义了所有五个字符(&< , >, '"), 这就是为什么我认为这个模块也应该。这也是对模块 plistlib 的一个很好的补充,例如函数 escape() 中 ElementTree 的参数 entities。该参数是一个带有要替换的其他字符的字典。 plistlib's 函数 save_plist() 的类似添加将是一个好主意,这样我们就可以转义其他字符。

我的解决方案基于所谓的猴子修补。基本上,我复制了整个函数 _escape(text) 并添加了额外的转义符('"):

from plistlib import _controlCharPat

def patched_escape(text):
    m = _controlCharPat.search(text)
    if m is not None:
        raise ValueError("strings can't contains control characters; "
                         "use bytes instead")
    text = text.replace("\r\n", "\n")       # convert DOS line endings
    text = text.replace("\r", "\n")         # convert Mac line endings
    text = text.replace("&", "&amp;")       # escape '&'
    text = text.replace("<", "&lt;")        # escape '<'
    text = text.replace(">", "&gt;")        # escape '>'
    text = text.replace("'", "&apos;")      # escape '''
    text = text.replace("\"", "&quot;")     # escape '"'

    return text

现在在我的脚本中,我将 plistlib's 函数 _escape(text) 替换为我的:

plistlib._escape = patched_escape

现在 plistlib 正确转义并保存 plists。关于猴子补丁的常见警告也适用于此。我没有其他来电者,只有这个脚本,所以这样做很好。