截断unicode,使其在编码进行电汇时符合最大尺寸

Jas*_*ith 27 python unicode json truncate

给定Unicode字符串和这些要求:

  • 该字符串被编码为一些字节序列格式(例如UTF-8或JSON unicode转义)
  • 编码的字符串具有最大长度

例如,iPhone推送服务需要JSON编码,最大总包数为256字节.

截断字符串以便重新编码为有效的Unicode并且它显示得相当正确的最佳方法是什么?

(人类语言理解不是必需的 - 截断的版本看起来很奇怪,例如对于孤立的组合字符或泰语元音,只要软件在处理数据时不会崩溃.)

也可以看看:

Den*_*ach 29

def unicode_truncate(s, length, encoding='utf-8'):
    encoded = s.encode(encoding)[:length]
    return encoded.decode(encoding, 'ignore')
Run Code Online (Sandbox Code Playgroud)

下面是unicode字符串的示例,其中每个字符用UTF-8中的2个字节表示:

>>> unicode_truncate(u'?????', 5)
u'\u0430\u0431'
Run Code Online (Sandbox Code Playgroud)


u0b*_*6ae 8

UTF-8的一个特性是它很容易重新同步,即在编码的字节流中很容易找到unicode字符边界.您需要做的就是以最大长度剪切编码的字符串,然后从末尾向后移动,删除大于127的任何字节 - 这些字节是多字节字符的一部分或开头.

正如现在所写,这太简单了 - 将擦除到最后的ASCII字符,可能是整个字符串.我们需要做的是检查没有截断的双字节(开头110yyyxx)三字节(1110yyyy)或四字节(11110zzz)

Python 2.6实现清晰的代码.优化不应成为问题 - 无论长度如何,我们只检查最后1-4个字节.

# coding: UTF-8

def decodeok(bytestr):
    try:
        bytestr.decode("UTF-8")
    except UnicodeDecodeError:
        return False
    return True

def is_first_byte(byte):
    """return if the UTF-8 @byte is the first byte of an encoded character"""
    o = ord(byte)
    return ((0b10111111 & o) != o)

def truncate_utf8(bytestr, maxlen):
    u"""

    >>> us = u"????????????"
    >>> s = us.encode("UTF-8")

    >>> trunc20 = truncate_utf8(s, 20)
    >>> print trunc20.decode("UTF-8")
    ??????
    >>> len(trunc20)
    18

    >>> trunc21 = truncate_utf8(s, 21)
    >>> print trunc21.decode("UTF-8")
    ???????
    >>> len(trunc21)
    21
    """
    L = maxlen
    for x in xrange(1, 5):
        if is_first_byte(bytestr[L-x]) and not decodeok(bytestr[L-x:L]):
            return bytestr[:L-x]
    return bytestr[:L]

if __name__ == '__main__':
    # unicode doctest hack
    import sys
    reload(sys)
    sys.setdefaultencoding("UTF-8")
    import doctest
    doctest.testmod()
Run Code Online (Sandbox Code Playgroud)

  • 如果您传递要序列化为 JSON 的字符串,请小心:如果字符串包含某些字符,这些字符将被转义,并且字符串的大小将会增加。您不能简单地将原始 UTF-8 截断为 X 字节。(假设字符串是 r'\\\\\\\\\\\\' -- X \'s。当序列化为 JSON 时,其大小会增加一倍。 (2认同)