【问题标题】:Easiest way to remove unicode representations from a string in python 3?从 python 3 中的字符串中删除 unicode 表示的最简单方法?
【发布时间】:2012-11-27 10:54:30
【问题描述】:

我在 python 3 中有一个字符串,其中有几个 unicode 表示,例如:

t = 'R\\u00f3is\\u00edn'

我想转换 t 以便在打印时它具有正确的表示形式,即:

>>> print(t)
Róisín

但是我只是取回了原始字符串。我已经尝试过 re.sub 和其他一些,但我似乎无法找到一种无需遍历每个字符即可更改这些字符的方法。 最简单的方法是什么?

【问题讨论】:

    标签: python string python-3.x escaping


    【解决方案1】:

    您想使用内置编解码器unicode_escape

    如果t 已经是bytes(8 位字符串),就这么简单:

    >>> print(t.decode('unicode_escape'))
    Róisín
    

    如果t 已经被解码为Unicode,您可以通过这种方式将其编码回bytes 然后decode。如果您确定您的所有 Unicode 字符都已转义,那么您使用什么编解码器进行编码实际上并不重要。否则,您可以尝试取回原始字节字符串,但它更简单,可能更安全,只强制任何未编码的字符进行编码,然后将它们与已经编码的字符一起解码:

    >>> print(t.encode('unicode_escape').decode('unicode_escape')
    Róisín
    

    如果您以后想知道如何使用正则表达式执行此类操作,请注意sub 允许您传递函数而不是repl 的模式。您可以通过调用int(hexstring, 16) 将任何十六进制字符串转换为整数,并使用chr 将任何整数转换为相应的Unicode 字符(请注意,这是Python 2 中不同的一位——您需要unichr)。所以:

    >>> re.sub(r'(\\u[0-9A-Fa-f]+)', lambda matchobj: chr(int(matchobj.group(0)[2:], 16)), t)
    Róisín
    

    或者,让它更清楚一点:

    >>> def unescapematch(matchobj):
    ...     escapesequence = matchobj.group(0)
    ...     digits = escapesequence[2:]
    ...     ordinal = int(digits, 16)
    ...     char = chr(ordinal)
    ...     return char
    >>> re.sub(r'(\\u[0-9A-Fa-f]+)', unescapematch, t)
    Róisín
    

    unicode_escape 编解码器实际上处理 \U\x\X、八进制 (\066) 和特殊字符 (\n) 序列以及 \u,它实现仅读取适当的最大位数的正确规则(\u 为 4,\U 为 8,等等,所以r'\\u22222' 解码为'∢2' 而不是'?'),可能还有更多我没有的东西没想到但这应该会给你这个想法。

    【讨论】:

    • 如果您使用的是以前的编码为 UTF-8 的版本,请不要;查看更新的版本,当您只有部分转义的字符串时应该更安全。
    • 我知道 re.sub 传递函数,但我不知道如何转换字符串,这太完美了,谢谢:)
    • @rptynan:你不知道chr,或者int的第二个参数吗?我会更新答案,以便以后出现的任何人都没有任何问题......
    • 以前学过,不过现在在重新学python,忘记了。
    • @rptynan:嗯,chr 不是你每天都在使用的东西,所以你不记得它也就不足为奇了。 (我经常用 Python 编写代码,但我仍然经常发现自己浪费了 5 分钟试图记住 unichr 在 3.x 中发生了什么,然后才想起它与 chr 合并……)
    【解决方案2】:

    首先,你要转换成什么是相当混乱的。

    想象一下,您可能想要转换为“o”和“i”。在这种情况下,您可以制作一张地图:

    mp = {u'\u00f3':'o', u'\u00ed':'i'}
    

    你可以像这样应用替换:

    t = u'R\u00f3is\u00edn'
    for i in range(len(t)):
        if t[i] in mp: t[i]=mp[t[i]]
    print t
    

    【讨论】:

    • 我很确定他想将 any Unicode 转义序列 u'\\uXXXX' 转换为 Unicode 字符 u'\uXXXX'
    • 是的,最好将其分回原始字符串,但如果需要,我可以自己处理。
    【解决方案3】:

    我很抱歉作为第二个答案发布,我没有评论 abarnert 解决方案的声誉。

    在使用他的函数处理了大约 50K 的 android 字符串后,我注意到对于某些用例还有另一个小的改进。

    我将 + 更改为 {1,4} 以处理有效十六进制字符跟随 4 位转义符的情况。

    我也将 int(escapesequence) 改为读取 int(digits)

    >>> def unescapematch(matchobj):
    ...     escapesequence = matchobj.group(0)
    ...     digits = escapesequence[2:]
    ...     ordinal = int(digits, 16)
    ...     char = unichr(ordinal)
    ...     return char
    
    >>> print re.sub(r'(\\u[0-9A-Fa-f]{1,4})', unescapematch, "Wi\u2011Fi")
    Wi‑Fi
    
    >>> print re.sub(r'(\\u[0-9A-Fa-f]+)', unescapematch, "Wi\u2011Fi")
    Traceback (most recent call last):
      File "<pyshell#102>", line 1, in <module>
        print re.sub(r'(\\u[0-9A-Fa-f]+)', unescapematch, "Wi\u2011Fi")
      File "C:\Python27\lib\re.py", line 151, in sub
         return _compile(pattern, flags).sub(repl, string, count)
      File "<pyshell#99>", line 5, in unescapematch
        char = unichr(ordinal)
    ValueError: unichr() arg not in range(0x10000) (narrow Python build)
    

    【讨论】:

      猜你喜欢
      • 2013-02-17
      • 2012-04-25
      • 2017-12-25
      • 2021-08-13
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 1970-01-01
      • 2013-09-18
      相关资源
      最近更新 更多