2009-09-25 26 views
18

Me gustaría probar el manejo Unicode de mi código. ¿Hay algo que pueda poner en random.choice() para seleccionar de todo el rango Unicode, preferiblemente no un módulo externo? Ni Google ni StackOverflow parecen tener una respuesta.Generar cadena UTF-8 aleatoria en Python

Editar: Parece que esto es más complejo de lo esperado, así que voy a reformular la pregunta - ¿Es suficiente el siguiente código para generar todos los non-control characters in Unicode válidos?

unicode_glyphs = ''.join(
    unichr(char) 
    for char in xrange(1114112) # 0x10ffff + 1 
    if unicodedata.category(unichr(char))[0] in ('LMNPSZ') 
    ) 
+0

Podría ser útil si tuviera que dar más detalles sobre "probar el manejo Unicode de mi código" y explicar cuál es la parte que genera cadenas UTF-8 aleatorias en esa prueba, y qué usted considera como "todo el rango Unicode" (16 bits? 21 bits? puntos de código no sustitutos? caracteres válidos (por ejemplo, no U + FFFF)?). ¿Confías en el códec Python UTF-8 o también necesitas probarlo? Python 2.X o 3.X o ambos? –

+1

El objetivo es aceptar cualquier punto de código Unicode imprimible (caracteres) como entrada para una interfaz web en Python 2.6. – l0b0

Respuesta

7
+0

Eso sería útil para asegurar que el programa no se rompa cuando se le da un texto incorrecto, pero no ayudaría como una prueba de conformidad. – voyager

+0

+1. l0b0: no te preocupes por generar unicode aleatorio. Tomando prestada la rueda de alguien más> reinventándola. –

+3

Buena respuesta, pero en realidad no responde la pregunta como se le pidió. – Kylotan

0

Desde Unicode es sólo un rango de - así - códigos, lo que acerca del uso de unichr() para obtener la cadena Unicode correspondiente a un número aleatorio entre 0 y 0xFFFF?
(Por supuesto que daría sólo un punto de código, por lo que repetir según sea necesario)

+3

Desafortunadamente, no es tan simple. Unicode contiene mucho más que 0x100000 caracteres, y el rango no está conectado. Por ejemplo, los valores sustitutos nunca deben aparecer como puntos de código único. Entonces la pregunta de qué forma una cadena UTF-8 válida es altamente no trivial. Los detalles se describen en la definición D92 del Capítulo 3 del Estándar Unicode. También hay una tabla (3-7) que enumera todas las posibilidades válidas para las secuencias de bytes UTF-8. – Philipp

+0

Veo, gracias :) – Joril

+0

Unicode se ejecuta desde U + 0000 a U + 10FFFF; también hay numerosos puntos de código que no son válidos, incluido (como ocurre) U + FFFF. El estándar Unicode dice de él " - se garantiza que el valor FFFF no es un carácter Unicode en absoluto". –

0

usted podría descargar un sitio web escrito en griego o alemán que utiliza Unicode y alimentar a que su código.

3

Depende de lo bien que desee realizar las pruebas y de la precisión con la que desea generar la generación. En su totalidad, Unicode es un conjunto de códigos de 21 bits (U + 0000 .. U + 10FFFF). Sin embargo, algunos trozos bastante grandes de ese rango se reservan para caracteres personalizados. ¿Desea preocuparse por generar caracteres combinados al comienzo de una cadena (porque solo deberían aparecer después de otro)?

El enfoque básico que adoptaría es generar aleatoriamente un punto de código Unicode (digamos U + 2397 o U + 31232), validarlo en contexto (es un carácter legítimo, puede aparecer aquí en la cadena) y codificar puntos de código válidos en UTF-8.

Si solo quiere comprobar si su código maneja correctamente UTF-8 con formato incorrecto, puede usar esquemas de generación mucho más simples.

Tenga en cuenta que debe saber qué esperar dada la entrada; de lo contrario, no está probando; estás experimentando

7

Aquí es una función de ejemplo que probablemente crea una secuencia aleatoria bien formado UTF-8, tal como se define en la Tabla 3-7 de Unicode 5.0.0:

#!/usr/bin/env python3.1 

# From Table 3–7 of the Unicode Standard 5.0.0 

import random 

def byte_range(first, last): 
    return list(range(first, last+1)) 

first_values = byte_range(0x00, 0x7F) + byte_range(0xC2, 0xF4) 
trailing_values = byte_range(0x80, 0xBF) 

def random_utf8_seq(): 
    first = random.choice(first_values) 
    if first <= 0x7F: 
     return bytes([first]) 
    elif first <= 0xDF: 
     return bytes([first, random.choice(trailing_values)]) 
    elif first == 0xE0: 
     return bytes([first, random.choice(byte_range(0xA0, 0xBF)), random.choice(trailing_values)]) 
    elif first == 0xED: 
     return bytes([first, random.choice(byte_range(0x80, 0x9F)), random.choice(trailing_values)]) 
    elif first <= 0xEF: 
     return bytes([first, random.choice(trailing_values), random.choice(trailing_values)]) 
    elif first == 0xF0: 
     return bytes([first, random.choice(byte_range(0x90, 0xBF)), random.choice(trailing_values), random.choice(trailing_values)]) 
    elif first <= 0xF3: 
     return bytes([first, random.choice(trailing_values), random.choice(trailing_values), random.choice(trailing_values)]) 
    elif first == 0xF4: 
     return bytes([first, random.choice(byte_range(0x80, 0x8F)), random.choice(trailing_values), random.choice(trailing_values)]) 

print("".join(str(random_utf8_seq(), "utf8") for i in range(10))) 

Debido a la gran extensión del estándar Unicode No puedo probar esto a fondo. También tenga en cuenta que los caracteres no están distribuidos por igual (pero cada byte en la secuencia es).

0

Respondiendo a la pregunta revisada:

Sí, en una definición estricta de los "caracteres de control" - en cuenta que no se incluyen CR, LF, y TAB; ¿Es eso lo que quieres?

Por favor, considere responder a mi invitación anterior para decirnos lo que realmente está tratando de hacer.

10

Las personas pueden encontrar su camino hasta aquí basándose principalmente en el título de la pregunta, así que aquí hay una forma de generar una cadena aleatoria que contenga una variedad de caracteres Unicode. Para incluir más (o menos) caracteres posibles, simplemente extienda esa parte del ejemplo con los rangos de puntos de código que desee.

import random 

def get_random_unicode(length): 

    try: 
     get_char = unichr 
    except NameError: 
     get_char = chr 

    # Update this to include code point ranges to be sampled 
    include_ranges = [ 
     (0x0021, 0x0021), 
     (0x0023, 0x0026), 
     (0x0028, 0x007E), 
     (0x00A1, 0x00AC), 
     (0x00AE, 0x00FF), 
     (0x0100, 0x017F), 
     (0x0180, 0x024F), 
     (0x2C60, 0x2C7F), 
     (0x16A0, 0x16F0), 
     (0x0370, 0x0377), 
     (0x037A, 0x037E), 
     (0x0384, 0x038A), 
     (0x038C, 0x038C), 
    ] 

    alphabet = [ 
     get_char(code_point) for current_range in include_ranges 
      for code_point in range(current_range[0], current_range[1] + 1) 
    ] 
    return ''.join(random.choice(alphabet) for i in range(length)) 

if __name__ == '__main__': 
    print('A random string: ' + get_random_unicode(10)) 
+0

Gracias, Jacob. ¿Habría algún problema al ejecutar este código en Python 2.7? – morfys

+1

@morfys No fue así, pero lo edité para que así sea. Gracias por preguntar. –

+0

¡Muchas gracias, Jacob! – morfys

2

sigue a un código que imprime cualquier carácter imprimible de UTF-8:

print(''.join(tuple(chr(l) for l in range(1, 0x10ffff) 
        if chr(l).isprintable()))) 

Todos los personajes están presentes, incluso los que no son manejados por la fuente utilizada. and not chr(l).isspace() se pueden agregar para filtrar todos los caracteres de espacio. (incluida la pestaña)

+0

Eso no te va a dar una cadena al azar, aunque por supuesto podrías usar ['random.sample'] (https://docs.python.org/2/library/random.html#random.sample) en su lugar de 'imprimir'. – l0b0

+0

'random.sample' no reemplaza los elementos que ya ha dibujado. –

+0

Así que use 'random.choices' en su lugar. – gimboland