Разбить строку в кодировке Юникод на куски по 300 байт без уничтожения символов - PullRequest
9 голосов
/ 18 мая 2011

Я хочу разделить u"an arbitrary unicode string" на куски, скажем, 300 байтов, не уничтожая никаких символов.Строки будут записаны в сокет, который ожидает utf8, используя unicode_string.encode("utf8").Я не хочу уничтожать персонажей.Как бы я это сделал?

Ответы [ 5 ]

10 голосов
/ 18 мая 2011

UTF-8 предназначен для этого.

def split_utf8(s, n):
    """Split UTF-8 s into chunks of maximum length n."""
    while len(s) > n:
        k = n
        while (ord(s[k]) & 0xc0) == 0x80:
            k -= 1
        yield s[:k]
        s = s[k:]
    yield s

Не проверено. Но вы найдете место для разделения, а затем возвращайтесь назад, пока не доберетесь до начала персонажа.

Однако, если пользователь когда-либо захочет увидеть отдельный фрагмент, вы можете вместо этого разделить границы кластера графемы. Это значительно сложнее, но не трудно. Например, в "é" вы могли бы не хотеть разделять "e" и "´". Или вам может быть все равно, если они в конце концов снова слипнутся.

5 голосов
/ 18 мая 2011

UTF-8 имеет специальное свойство, состоящее в том, что все символы продолжения 0x80 - 0xBF (начинаются с битов 10). Так что просто убедитесь, что вы не разбили прямо перед одним.

Что-то вроде:

def split_utf8(s, n):
    if len(s) <= n:
        return s, None
    while ord(s[n]) >= 0x80 and ord(s[n]) < 0xc0:
        n -= 1
    return s[0:n], s[n:]

должен сделать трюк.

2 голосов
/ 18 мая 2011

Проверено.

def split_utf8(s , n):
    assert n >= 4
    start = 0
    lens = len(s)
    while start < lens:
        if lens - start <= n:
            yield s[start:]
            return # StopIteration
        end = start + n
        while '\x80' <= s[end] <= '\xBF':
            end -= 1
        assert end > start
        yield s[start:end]
        start = end
0 голосов
/ 18 мая 2011

Используйте кодировку Unicode, которая по своему дизайну имеет фиксированную длину каждого символа, например utf-32:

>>> u_32 = u'Юникод'.encode('utf-32')
>>> u_32
'\xff\xfe\x00\x00.\x04\x00\x00=\x04\x00\x008\x04\x00\x00:\x04\x00\x00>\x04\x00\x
004\x04\x00\x00'
>>> len(u_32)
28
>>> len(u_32)%4
0
>>>

После кодирования вы можете отправить чанк любого размера (размер должен быть кратен 4 байтам) без уничтожения символов

0 голосов
/ 18 мая 2011

Если вы можете быть уверены, что представление ваших символов в utf-8 имеет длину всего 2 байта, вы можете безопасно разделить строку юникода на порции по 150 символов (это должно быть верно для большинства европейских кодировок). Но utf-8 - это кодирование с переменной шириной. Так что может разбить строку юникода на отдельные символы, преобразовать каждый символ в utf-8 и заполнить ваш буфер, пока вы не достигнете максимального размера фрагмента ... это может быть неэффективным и проблемой, если необходима высокая пропускная способность

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...