Codificación porcentual de una cadena

13

Introducción

Como algunos de ustedes saben, las URL realmente tienen una lista de caracteres que hacen cosas especiales. Por ejemplo, el /carácter separa las partes de la URL, y el ?, &y =los personajes se utiliza para pasar parámetros de consulta al servidor. De hecho, hay un montón de personajes con funciones especiales $&+,/:;=?@. Cuando necesite usar estos caracteres en la URL por cualquier otro motivo además de las funciones especiales, debe hacer algo llamado codificación porcentual .

La codificación porcentual es cuando tomas el valor hexadecimal de un %personaje y antepones un carácter al comienzo del mismo. Por ejemplo, el carácter ?se codificaría como %3F, y el carácter &se codificaría como %26. En una URL específicamente, esto le permite enviar estos caracteres como datos a través de la URL sin causar problemas de análisis. Su desafío será tomar una cadena y codificar en porcentaje todos los caracteres que deben codificarse.

El reto

Deberá escribir un programa o función que tome una sola cadena que consta de caracteres con puntos de código 00-FF (caracteres ASCII y ASCII extendido). Luego tendrá que generar o devolver la misma cadena con cada carácter codificado porcentual si es necesario. Los elementos integrados que realizan esta tarea no están permitidos, ni las lagunas estándar. Como referencia, aquí hay una lista de todos los caracteres que deben codificarse en porcentaje:

  • Caracteres de control (puntos de código 00-1F y 7F)
  • Caracteres ASCII extendidos (puntos de código 80-FF)
  • Caracteres reservados ( $&+,/:;=?@es decir, puntos de código 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • Caracteres inseguros ( " <>#%{}|\^~[]`es decir, puntos de código 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

Aquí hay una misma lista, pero en cambio como una lista de puntos de código decimales:

0-31, 32, 34, 35, 36, 37, 38, 43, 44, 47, 58, 59, 60, 62, 61, 63, 64, 91, 92, 93, 94, 96, 123, 124, 125, 126, 127, 128-255

Este es el código de golf, por lo que gana el código más corto en bytes (o método de puntuación alternativo aprobado).

Casos de prueba

http://codegolf.stackexchange.com/  =>  http%3A%2F%2Fcodegolf.stackexchange.com%2F
[@=>]{#}  =>  %5B%40%3D%3E%5D%7B%23%7D
Test String  =>  Test%20String
ÑÉÐÔ®  =>  %D1%C9%D0%D4%AE
  =>  %0F%16%7F (Control characters 0F, 16, and 7F)
 ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ  =>  %80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF (Extended ASCII characters 80-FF)
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  =>  %20!%22%23%24%25%26'()*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E
GamrCorps
fuente
¿Tendrías un caso de prueba que muestre los caracteres de control?
Leaky Nun
@LeakyNun hecho.
GamrCorps
Estoy seguro de que codepoint EFno contiene el signo de interrogación.
user48538
@ zyabin101 ¿dónde encontraste eso? No lo estoy viendo.
GamrCorps
"Por ejemplo, el carácter? Se codificaría como% EF ..."
user48538

Respuestas:

2

Pyth, 30 28 26 bytes

L?hx+G+rG1CGbb+\%.HCbsmydz

pruébalo en línea

Explicación

L?hx+G+rG1CGbb+\%.HCbsmydz
L?hx+G+rG1CGbb+\%.HCb       First part, L defines the function y(b)
 ?hx+G+rG1CGbb+\%.HCb       ? is the ternary operator
  hx+G+rG1CGb               This part will be evaluated
  hx                        x will find the first occurence of a
                            character in a list. If it doesn't
                            find one, it will return -1. hx then
                            equals 0 (or false).
    +G+rG1CG                The list of allowed characters, a
                            concetanation (+) of the alphabet (G),
                            uppercase alphabet (rG1) and numbers
                            (CG, see below for details)
            b               The character to find in the list
             b              True branch of the ternary operator,
                            the character is allowed and returned.
              +\%.HCb       False branch, convert to hex and add %
                     smydz  The actual program
                      mydz  Map every character in the input (z)
                            using the function y on every d
                     s      Join the array, and implicit print.

CGEs este truco que genera un gran número que contiene todos los dígitos posibles. Esto es perfecto, ya que no nos importan los duplicados al verificar si una cadena está en otra.

Lars
fuente
Esta respuesta no cumple con las especificaciones de la pregunta. Hay más personajes permitidos que solo A-Za-z0-9. Por ejemplo, .debe conservarse en lugar de traducirse a %2E. (cc: @GamrCorps)
DLosc
3

Vim, 67 bytes / pulsaciones de teclas

:s/\c[^a-z!'()*0-9._-]/\='%'.printf("%02x",char2nr(submatch(0)))/g<cr>

Tenga en cuenta que <cr>representa la tecla Intro, p. Ej.0x0D que es un solo byte.

Esta es una solución bastante sencilla. Explicación:

:s/                                                                    "Search and replace
   \c                                                                  "Case-insensitive
     [^a-z!'()*0-9._-]/                                                "A negative range. Matches any character not alphabetc, numeric or in "!'()*0-9._-"
                       \=                                              "Evaluate
                         '%'                                           "a percent sign string
                            .                                          "Concatenated with
                             printf("%02x",char2nr(submatch(0)))       "The hex value of the character we just matched
                                                                /g     "Make this apply to ever match
                                                                  <cr> "Actually run the command

Esa printf("%02x",char2nr(submatch(0)))basura es terriblemente fea .

James
fuente
"Esa printf("%02x",char2nr(submatch(0)))basura es terriblemente antipática" y extremadamente hacky
Leaky Nun
2

Perl, 40 bytes

Código de 39 bytes + -p.

Un poco cojo, pero creo que es la solución más corta ...

s/[^!'()*-.\w]/sprintf'%%%02x',ord$&/ge

Uso

echo -n ' !"#$%&'\''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqstuvwxyz{|}~' | perl -pe "s/[^'()*-.\w]/sprintf'%%%02x',ord$&/ge"
%20%21%22%23%24%25%26'()*+,-.%2f0123456789%3a%3b%3c%3d%3e%3f%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5b%5c%5d%5e_%60abcdefghijklmnopqstuvwxyz%7b%7c%7d%7e
Dom Hastings
fuente
1

Python 3, 92 bytes

5 bytes gracias a orlp.

1 byte gracias a Sp3000.

import re;lambda s:''.join(re.match("[!'-*.0-9\w-]",c,256)and c or'%%%02X'%ord(c)for c in s)

Ideone it!

Monja permeable
fuente
re.match("[!'()*.0-9A-Za-z_-]",c)and c or'%%%02X'%ord(c)
orlp
@ Sp3000 \wincluye ASCII extendido
Leaky Nun
Además, '()*->'-*
Sp3000
Creo que \wfunciona con la opción 256( re.ASCII): ideone . Definitivamente funciona en Python 3 en ideone, y debería funcionar con u"..."cadenas en Python 2, pero ideone parece hacer cosas extrañas a este último (por ejemplo, print len(u"ÑÉÐÔ®")da 10 en ideone pero 5 en repl.it y mi computadora, a pesar de ser 2.7. 10)
Sp3000
1

C, 83 bytes

f(char*p){for(;*p;++p)printf(isalnum(*p)||strchr("!'()*-._",*p)?"%c":"%%%02X",*p);}
orlp
fuente
1

Python, 86 bytes

lambda s:"".join(["%%%02X"%ord(c),c][c<"{"and c.isalnum()or c in"!'()*-._"]for c in s)

Puerto de mi respuesta C.

orlp
fuente
1

Rubí, 37 + 3 = 40 bytes

Ejecutar con -p(3 bytes adicionales), como $ ruby -p percent_encode.rb:

gsub(/[^\w!'()*-.]/){"%%%02X"%$&.ord}
daniero
fuente
1

Jalea , 28 27 bytes

ḟØWḟ©“!'()*-.”Od⁴‘ịØH”%p®,y

Este es un enlace monádico. Pruébalo en línea!

Cómo funciona

ḟØWḟ©“!'()*-.”Od⁴‘ịØH”%p®,y  Monadic link. Argument: s (string)

 ØW                          Yield “0...9A...Z_a...z”.
ḟ                            Remove these characters from s.
     “!'()*-.”               Yield “!'()*-.”.
   ḟ                         Remove these characters from s.
    ©                        Copy the result to the register.
              O              Ordinal; get the code point of each character.
               d⁴            Divmod 16; yield quotient and remainder modulo 16.
                 ’           Decrement the results.
                  ịØH        Index into “0123456789ABCDEF”.
                     ”p%     Perform Cartesian product with ”%, prepending it to
                             each pair of hexadecimal digits.
                        ®,   Yield [t, r], where t is the string in the register
                             and r the result of the Cartesian product.
                          y  Use this pair to perform transliteration on s.
Dennis
fuente
1

Haskell 201 179 178 127 119 bytes

import Data.Char;import Numeric;f=(=<<)(\c->if isAlphaNum c&&isAscii c||elem c"-_.~"then[c]else '%':(showHex$ord c)"")

Sin golf:

import Data.Char
import Numeric

f=(=<<) e
e c = if isAlphaNum c && isAscii c && c `elem` "-_.~" then [c] else '%' : (showHex $ ord c) ""
sham1
fuente
¿Puedes eliminar un montón de espacios?
Rɪᴋᴇʀ
Puede perder el where, convertir los ifguardias, hacer e parcial, perder el último argumento de showHex, en línea p, en línea s, perder la firma, reordenar elemy perder aún más espacio en blanco. Como primera aproximación llegué a 118 de esa manera.
MarLinn
Gracias @MarLinn por un montón de buenas sugerencias para recortar el código. Sin embargo, tuve algunos problemas con ciertas sugerencias. En primer lugar, si elimino la firma, GHC se quejará de eso No instance for (Foldable t0) arising from a use of ‘foldr’. Dice que el tipo de la función es ambigua, lo que resulta en un enlace inferido de f :: t0 Char -> [Char]. Y en segundo lugar, no pude eliminar el argumento de la cadena vacía de showHex ya que devuelve un ShowS, que es un alias de tipo para la String -> Stringnecesidad de la cadena vacía.
sham1
@ sham1, sí, ShowStoma una cadena ... pero tienes una: con la que estás agregando (++). Entonces puedes perder ambos al mismo tiempo. Eso es realmente por qué se ShowSve de esa manera. No obtengo el error de tipo, así que supongo que es una cosa de versión. Otras dos cosas que noté por ahora: otherwisesiempre se pueden reemplazar por 1<2(una abreviatura de True), pero si regresas a ifen su lugar puedes alinear ey soltar todos los nombres. E incluso convertir el pliegue en a concatMap, es decir, a (>>=). No ahorra mucho, pero al menos un poco. También podría resolver el error de tipo.
MarLinn
0

Python 2, 78 bytes

lambda s:"".join(["%%%02x"%ord(c),c][c.isalnum()or c in"!'()*-._"]for c in s)

Más bien formateado:

lambda s:
    "".join(["%%%02x" % ord(c), c][c.isalnum() or c in"!'()*-._"] for c in s)
Byte Commander
fuente
0

SQF , 199 176

Usando el formato de función como archivo:

i="";a="0123456789ABCDEF!'()*-.GHIJKLMNOPQRSTUVWXYZ_";{i=i+if((toUpper _x)in a)then{_x}else{x=(toArray[_x])select 0;"%"+(a select floor(x/16))+(a select(x%16))}}forEach _this;i

Llamar como "STRING" call NAME_OF_COMPILED_FUNCTION

Οurous
fuente
0

PowerShell v2 +, 146 bytes

param($n)37,38+0..36+43,44,47+58..64+91,93+96+123..255-ne33|%{$n=$n-replace"[$([char]$_)]",("%{0:x2}"-f$_)};$n-replace'\\','%5c'-replace'\^','%5e'

Mucho tiempo porque quería mostrar un enfoque diferente en lugar de simplemente copiar y pegar la misma cadena de expresiones regulares que todos los demás están usando.

En cambio, aquí, recorremos cada punto de código que debe estar codificado en porcentaje, y hacemos un literal -replaceen la cadena de entrada $ncada iteración (volviendo a guardar $n). Luego, debemos tener en cuenta los dos caracteres especiales que necesitan escapar \y ^, por lo tanto, están en -replaceelementos separados al final. Como no volvimos a guardar esa cadena final, se dejó en la tubería y la impresión es implícita.

AdmBorkBork
fuente
0

Conjunto x86 de 16/32 bits, 73 bytes

Código de bytes:

AC 3C 21 72 2A 74 3E 3C 26 76 24 3C 2B 72 36 3C
2C 76 1C 3C 2F 72 2E 74 16 3C 3A 72 28 74 10 3C
5F 74 22 50 0C 60 3C 60 74 02 3C 7B 58 72 16 D4
10 3C 09 1C 69 2F 86 E0 3C 09 1C 69 2F 92 B0 25
AA 92 AA 86 E0 AA E2 B8 C3

Desmontaje

l0: lodsb         ;fetch a character
    cmp  al, 21h
    jb   l1       ;encode 0x00-0x20
    je   l2       ;store 0x21
    cmp  al, 26h
    jbe  l1       ;encode 0x22-0x26
    cmp  al, 2bh
    jb   l2       ;store 0x27-0x2A
    cmp  al, 2ch
    jbe  l1       ;encode 0x2B-0x2C
    cmp  al, 2fh
    jb   l2       ;store 0x2D-0x2E
    je   l1       ;encode 0x2F
    cmp  al, 3ah
    jb   l2       ;store 0x30-0x39
    je   l1       ;encode 0x3A
    cmp  al, 5fh
    je   l2       ;store 0x5F
    push eax
    or   al, 60h  ;merge ranges
    cmp  al, 60h
    je   l3       ;encode 0x40, 0x60
    cmp  al, 7bh
l3: pop  eax
    jb   l2       ;store 0x41-0x5A, 0x61-0x7A
                  ;encode 0x3B-0x3F, 0x5B-0x5E, 0x7B-0xFF

l1: aam  10h      ;split byte to nibbles
    cmp  al, 9    ;convert 0x0A-0x0F 
    sbb  al, 69h  ;to
    das           ;0x41-0x46 ('A'-'F')
    xchg ah, al   ;swap nibbles
    cmp  al, 9    ;do
    sbb  al, 69h  ;other
    das           ;half
    xchg edx, eax ;save in edx
    mov  al, '%'
    stosb         ;emit '%'
    xchg edx, eax
    stosb         ;emit high nibble
    xchg ah, al

l2: stosb         ;emit low nibble or original character
    loop l0       ;until end of string
    ret

Llame con:
- esi = puntero al búfer que contiene la cadena de origen;
- edi = puntero al búfer que recibe una cadena codificada;
- ecx = longitud de la cadena de origen.

Peter Ferrie
fuente