Punycode es una representación de Unicode con el subconjunto de caracteres ASCII limitado que se utiliza para los nombres de host de Internet . Con Punycode, los nombres de host que contienen caracteres Unicode se transcodifican a un subconjunto de ASCII que consta de letras, dígitos y guiones, que se denomina subconjunto letra-dígito-guión (LDH). Por ejemplo, München ( nombre alemán de Múnich ) se codifica como Mnchen-3ya .
Si bien el Sistema de nombres de dominio (DNS) técnicamente admite secuencias arbitrarias de octetos en las etiquetas de los nombres de dominio, los estándares DNS recomiendan el uso del subconjunto LDH de ASCII que se utiliza convencionalmente para los nombres de host y requieren que las comparaciones de cadenas entre nombres de dominio DNS no distingan entre mayúsculas y minúsculas. La sintaxis Punycode es un método de codificación de cadenas que contienen caracteres Unicode, como los nombres de dominio internacionalizados (IDNA), en el subconjunto LDH de ASCII que prefiere el DNS. Se especifica en la Solicitud de comentarios 3492 de la IETF. [1]
Como se indica en el RFC 3492, "Punycode es una instancia de un algoritmo más general llamado Bootstring , que permite que cadenas compuestas a partir de un pequeño conjunto de puntos de código 'básicos' representen de forma única cualquier cadena de puntos de código extraídos de un conjunto más grande". Punycode define parámetros para el algoritmo general Bootstring para que coincidan con las características del texto Unicode. Esta sección demuestra el procedimiento para la codificación Punycode, utilizando el ejemplo de la cadena "bücher" ( Bücher es la palabra alemana para libros ), que se traduce a la etiqueta "bcher-kva".
Para simplificar los algoritmos de codificación y decodificación, no se ha intentado evitar que algunos valores codificados codifiquen valores Unicode inadmisibles: sin embargo, estos deben verificarse y detectarse durante la decodificación.
Punycode está diseñado para funcionar en todos los sistemas de escritura y para optimizarse automáticamente al intentar adaptarse a los rangos de conjuntos de caracteres dentro de la cadena a medida que opera. Está optimizado para el caso en que la cadena esté compuesta por cero o más caracteres ASCII y, además, caracteres de solo otro sistema de escritura, pero se adaptará a cualquier cadena Unicode arbitraria. Tenga en cuenta que para el uso de DNS, se supone que la cadena de nombre de dominio se ha normalizado utilizando nameprep y (para dominios de nivel superior ) se ha filtrado contra una tabla de idioma registrada oficialmente antes de ser codificada con punycode, y que el protocolo DNS establece límites en las longitudes aceptables de la cadena Punycode de salida.
En primer lugar, se copian todos los caracteres ASCII de la cadena de la entrada a la salida, omitiendo cualquier otro carácter. Por ejemplo, "bücher" se copia en "bcher". Si se copió algún carácter, es decir, si había al menos un carácter ASCII en la entrada, se añade un guión ASCII a la salida (por ejemplo, "bücher" → "bcher-", pero "ü" → "").
Tenga en cuenta que los guiones son en sí mismos caracteres ASCII. Por lo tanto, pueden estar presentes en la entrada y, de ser así, se copiarán en la salida. Esto no genera ninguna ambigüedad: si la salida contiene guiones, el que se agrega siempre es el último. Marca el final de los caracteres ASCII.
Los caracteres que no son ASCII se ordenan por valor Unicode, comenzando por el más bajo (si un carácter aparece más de una vez, se ordenan por posición). Cada uno de ellos se codifica como un único número. Este único número define tanto la ubicación donde se insertará el carácter como el carácter que se insertará.
El número codificado es n × j + i . Al dividir por n y obtener también el resto, un decodificador puede determinar j e i .
Hay seis lugares posibles para insertar un carácter en la cadena "bcher" (incluyendo antes del primer carácter y después del último). Hay 124 puntos de código entre el último punto de código ASCII (127 = 0x7F , el final de ASCII) y ü (punto de código 252 = 0xFC , consulte el Suplemento Latin-1 de Unicode ). La ü se inserta en la posición 1, después de la b . Por lo tanto, el codificador sumará el número (6 × 124) + 1 = 745 , y el decodificador puede recuperarlos mediante ⌊745 ÷ 6⌋ = 124 y 745 mod 6 = 1 .
Estos números son estrictamente crecientes. Para el segundo carácter insertado y los siguientes, se escribe la diferencia entre el número y el anterior.
El número se codifica con las letras de la a a la z y los dígitos del 0 al 9. No se trata de un sistema de base 36, sino de un sistema más complejo que se describe a continuación y que permite concatenar los números sin que haya nada que los separe.
Punycode utiliza números enteros de longitud variable generalizados para representar estos valores. Por ejemplo, así es como se utiliza "kva" para representar el código numérico 745:
Se utiliza un sistema numérico con ordenación little-endian que permite códigos de longitud variable sin delimitadores separados: un dígito inferior a un valor umbral marca que es el dígito más significativo, por lo tanto, el final del número. El valor umbral depende de la posición en el número y también de inserciones anteriores, para aumentar la eficiencia. En consecuencia, los pesos de los dígitos varían.
En este caso se utiliza un sistema numérico con 36 símbolos, donde los números decimales del 0 al 25 son iguales a los números 'a' a 'z', que no distinguen entre mayúsculas y minúsculas, y los números decimales del 26 al 35 son iguales a los números '0' a '9'. Por lo tanto, "kva" corresponde a la cadena de números decimales "10 21 0".
Para decodificar esta cadena de símbolos, se necesitará una secuencia de umbrales, en este caso es (1, 1, 26, 26, ...). [2] El peso (o valor posicional ) del dígito menos significativo es siempre 1: 'k' (=10) con un peso de 1 es igual a 10. Después de esto, el peso del siguiente dígito depende del primer umbral: generalmente, para cualquier n , el peso del ( n +1)-ésimo dígito es w × (36 − t ), donde w es el peso anterior y t es el umbral del n -ésimo dígito. En este caso, el segundo símbolo tiene un valor posicional de 36 menos el valor umbral anterior de 1, lo que da como resultado 35. Por lo tanto, la suma de los dos primeros símbolos "k" (=10) y "v" (=21) es 10 × 1 + 21 × 35. Como el segundo símbolo no es menor que su valor umbral de 1, hay más por venir. Sin embargo, como el tercer símbolo en este ejemplo es "a" (=0), podemos ignorar el cálculo de su peso. Por lo tanto, "kva" representa el número decimal (10 × 1) + (21 × 35) = 745.
El número 745 se codificará como 10 + 21 × 35 + 0 (se utiliza la base 35 para el segundo dígito, el dígito más significativo 0 se necesita como terminador), 10 → 'k', 21 → 'v', 0 → 'a', entonces "bücher" → "bcher-kva".
Los umbrales en sí se determinan para cada carácter codificado sucesivo mediante un algoritmo que los mantiene entre 1 y 26 inclusive. [3] El caso se puede utilizar entonces para proporcionar información sobre el caso original de la cadena. [4]
Como los caracteres especiales se ordenan por sus puntos de código mediante un algoritmo de codificación, para la inserción de un segundo carácter especial en "bücher", la primera posibilidad es "büücher" con el código "bcher-kvaa", la segunda "bücüher" con el código "bcher-kvab", etc. Después de "bücherü" con el código "bcher-kvae" vienen los códigos que representan la inserción de ý, el carácter Unicode que sigue a ü, comenzando con "ýbücher" con el código "bcher-kvaf" (distinto de "übücher" codificado "bcher-jvab"), etc.
Para evitar que los guiones en nombres de dominio no internacionales activen una decodificación de Punycode, la cadena xn--
se antepone a las secuencias de Punycode en los nombres de dominio internacionalizados. Esto se denomina ACE (codificación compatible con ASCII). [5]
De esta forma, el nombre de dominio "bücher.tld" se representaría en una URL como "xn--bcher-kva.tld".
La siguiente tabla muestra ejemplos de codificaciones Punycode para diferentes tipos de entrada. [6]
s.encode("punycode")
). Ver la página de discusión .