Divide la cadena Unicode en trozos de 300 bytes sin destruir los caracteres

Quiero dividir u"an arbitrary unicode string" en trozos de, por ejemplo, 300 bytes sin destruir ningún carácter. Las cadenas se escribirán en un socket que espera utf8 mediante unicode_string.encode("utf8") . No quiero destruir ningún personaje. ¿Cómo haría esto?

UTF-8 está diseñado para esto.

 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 

No probado. Pero encuentras un lugar para dividir, luego retrocedes hasta llegar al principio de un personaje.

Sin embargo, si un usuario desea alguna vez ver un fragmento individual, es posible que desee dividirse en los límites del grupo de grafemas en su lugar. Esto es significativamente más complicado, pero no intratable. Por ejemplo, en "é" , es posible que no desee dividir la "e" y la "´" . O puede que no te importe, siempre que se queden pegados de nuevo al final.

UTF-8 tiene una propiedad especial de que todos los caracteres de continuación son 0x800xBF (comienza con los bits 10). Así que asegúrate de no dividirte antes de una.

Algo a lo largo de las líneas de:

 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:] 

debe hacer el truco

Probado

 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 

Si puede asegurarse de que la representación en utf-8 de sus caracteres tenga una longitud de solo 2 bytes, debería ser seguro dividir la cadena Unicode en fragmentos de 150 caracteres (esto debería ser cierto para la mayoría de las codificaciones europeas). Pero utf-8 es una encoding de ancho variable. Por lo tanto, podría dividir la cadena Unicode en caracteres individuales, convertir cada carácter a utf-8 y llenar su búfer hasta que scope el tamaño máximo de fragmento … esto podría ser ineficaz y un problema si el alto rendimiento es una necesidad …

Utilice la encoding Unicode que, por diseño, tiene una longitud fija de cada carácter, por ejemplo, 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 >>> 

Después de la encoding, puede enviar una porción de cualquier tamaño (el tamaño debe ser múltiplo de 4 bytes) sin destruir los caracteres