2011-05-18 18 views

Respuesta

10

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 comienzo de un personaje.

Sin embargo, si un usuario alguna vez desea ver un fragmento individual, es posible que desee dividir los límites del clúster de grafemas en su lugar. Esto es significativamente más complicado, pero no difícil de resolver. Por ejemplo, en "é", podría no desea dividir el "e" y el "´". O puede que no te importe, siempre y cuando se unan nuevamente al final.

+0

Probé esto y parece funcionar. Aunque los usuarios finales verán los trozos, considero que esta solución es lo suficientemente buena. Tras algunas lecturas rápidas, los límites del grupo de grafemas parecían muy difíciles de implementar. No lo necesito en este momento. Es '(ord (s [k]) & 0xc0) == 0x80' lo mismo que' "\ x80" <= s [k] <= "\ xBF" '? Sí encontré esto cuidadosamente elaborado – runfalk

+1

Sí, son equivalentes. Estoy algo acostumbrado a escribir el código de manejo UTF-8 en C, lo que explica el estilo. Usa el estilo que te parezca mejor. –

0

Si puede asegurarse de que la representación del utf-8 de sus caracteres es de solo 2 bytes de longitud, debería separar la cadena unicode en segmentos de 150 caracteres (esto debería ser cierto para la mayoría de las codificaciones europeas). Pero utf-8 es una codificación de ancho variable. Por lo tanto, podría dividir la cadena Unicode en caracteres únicos, convertir cada char a utf-8 y llenar el búfer hasta que alcance el tamaño máximo de fragmento ... esto podría ser ineficiente y un problema si el alto rendimiento es una necesidad ...

+0

Habrá más codificaciones europeas. Tanto chinos como japoneses definitivamente estarán representados. Alto rendimiento no es requerido. Sin embargo, esperaba que hubiera una solución más bonita. – runfalk

+3

Bueno, los caracteres convertidos en utf-8 son como máximo de 4 bytes de longitud. Así que los juncos de 75 caracteres por 4 hacen 300 bytes para estar en el lado más seguro. –

5

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

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.

+0

'si len (s <= n)' ??? –

+0

@John Fixxored. – badp

-2

Uso codificación Unicode que por diseño tienen una longitud fija de cada personaje, 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 codificación puede enviar trozo de cualquier tamaño (tamaño debe ser múltiplo de 4 bytes) sin destruir caracteres

+1

Esto no es posible ya que el servidor espera UTF-8 – runfalk

2

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 
Cuestiones relacionadas