Codifica in percentuale una stringa


13

introduzione

Come alcuni di voi sanno, gli URL in realtà hanno un elenco di caratteri che fanno cose speciali. Ad esempio, il /carattere separa parti dell'URL, e ?, &e =caratteri vengono utilizzati per passare di query parametri al server. In realtà, v'è un gruppo di caratteri con funzioni speciali: $&+,/:;=?@. Quando devi utilizzare questi caratteri nell'URL per qualsiasi altro motivo oltre alle funzioni speciali, devi fare qualcosa chiamato codifica percentuale .

La codifica percentuale avviene quando si prende il valore esadecimale di un %personaggio e si antepone un carattere all'inizio di esso. Ad esempio, il personaggio ?verrebbe codificato come %3Fe il personaggio &verrebbe codificato come %26. In un URL in particolare, ciò consente di inviare questi caratteri come dati tramite l'URL senza causare problemi di analisi. La tua sfida sarà quella di prendere una stringa e codificare in percentuale tutti i caratteri che devono essere codificati.

La sfida

Dovresti scrivere un programma o una funzione che accetta una singola stringa composta da caratteri con punti di codice 00-FF (caratteri ASCII ed ASCII estesi). Dovrai quindi generare o restituire la stessa stringa con ogni carattere codificato in percentuale, se necessario. Non sono consentiti built-in che svolgono questo compito, né scappatoie standard. Per riferimento, ecco un elenco di tutti i caratteri che devono essere codificati in percentuale:

  • Caratteri di controllo (Codepoints 00-1F e 7F)
  • Caratteri ASCII estesi (Codepoints 80-FF)
  • Caratteri riservati ( $&+,/:;=?@ovvero codici di riferimento 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • Caratteri non sicuri ( " <>#%{}|\^~[]`ovvero punti di codice 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

Ecco uno stesso elenco, ma invece come un elenco di punti decimali:

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

Questo è il codice golf, quindi vince il codice più breve in byte (o metodo di punteggio alternativo approvato)!

Casi test

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

Avresti una testcase che mostra i personaggi di controllo?
Leaky Nun,

@LeakyNun fatto.
GamrCorps,

Sono sicuro che il punto di codice EFnon contenga il punto interrogativo.
user48538

@ zyabin101 dove l'hai trovato? Non lo vedo.
GamrCorps,

"Ad esempio, il personaggio? Sarebbe codificato come% EF ..."
user48538

Risposte:


2

Pyth, 30 28 26 byte

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

provalo online

Spiegazione

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.

CG è questo trucco che genera un numero enorme che contiene tutte le cifre possibili. Questo è perfetto, poiché non ci importa dei duplicati quando controlliamo se una stringa è in un'altra.


Questa risposta non soddisfa le specifiche nella domanda. Ci sono più personaggi consentiti che semplici A-Za-z0-9. Ad esempio, .dovrebbe essere preservato anziché tradotto in %2E. (cc: @GamrCorps)
DLosc

3

Vim, 67 byte / sequenze di tasti

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

Nota che <cr> rappresenta la chiave di invio, ad es. 0x0DChe è un singolo byte.

Questa è una soluzione piuttosto semplice. Spiegazione:

: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

Quella printf("%02x",char2nr(submatch(0)))spazzatura è terribilmente ungolfy .


"Quella printf("%02x",char2nr(submatch(0)))spazzatura è terribilmente ungolfy" ed estremamente caotica
Leaky Nun

2

Perl, 40 byte

39 byte codice + -p.

Un po 'zoppo, ma penso che sia la soluzione più breve ...

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


1

Python 3, 92 byte

5 byte grazie a orlp.

1 byte grazie 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 esso!


re.match("[!'()*.0-9A-Za-z_-]",c)and c or'%%%02X'%ord(c)
orlp

@ Sp3000 \winclude ASCII esteso
Leaky Nun

Inoltre, '()*->'-*
Sp3000,

Penso che funzioni\w con l' opzione 256( re.ASCII): ideone . Funziona sicuramente in Python 3 su ideone e dovrebbe funzionare con le u"..."stringhe in Python 2, ma ideone sembra fare cose funky a quest'ultimo (ad esempio, print len(u"ÑÉÐÔ®")dà 10 su ideone ma 5 su repl.it e il mio computer, nonostante sia tutto 2.7. 10)
Sp3000,

1

C, 83 byte

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

1

Python, 86 byte

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

Porta della mia risposta C.


1

Rubino, 37 + 3 = 40 byte

Esegui con -p(3 byte extra), come $ ruby -p percent_encode.rb:

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

1

Gelatina , 28 27 byte

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

Questo è un collegamento monadico. Provalo online!

Come funziona

ḟØ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.

1

Haskell, 201 179 178 127 119 byte

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

Ungolfed:

import Data.Char
import Numeric

f=(=<<) e
e c = if isAlphaNum c && isAscii c && c `elem` "-_.~" then [c] else '%' : (showHex $ ord c) ""

Riesci a rimuovere un mucchio di spazi?
Rɪᴋᴇʀ

Puoi perdere il where, trasformare il ifin guardie, rendere parziale, perdere l'ultimo argomento di showHex, inline p, inline s, perdere la firma, riordinare eleme perdere ancora più spazi bianchi. Come prima approssimazione sono sceso a 118 in quel modo.
MarLinn,

Grazie @MarLinn per un sacco di buoni suggerimenti su come ridurre il codice. Tuttavia, ho avuto qualche problema con alcuni suggerimenti. Prima di tutto, se rimuovo la firma, GHC si lamenterà di ciò No instance for (Foldable t0) arising from a use of ‘foldr’. Dice che il tipo di funzione è ambiguo, risultante in un'associazione inferita di f :: t0 Char -> [Char]. E in secondo luogo, non ho potuto rimuovere l'argomento stringa vuota da showHex in quanto restituisce ShowS, che è un alias di tipo per String -> Stringaver quindi bisogno della stringa vuota.
sham1

@ sham1, sì, ShowSprende una stringa ... ma ne hai una: quella con cui stai aggiungendo (++). Quindi puoi perdere entrambi allo stesso tempo. Ecco perché ShowSsembra così. Non visualizzo l'errore di tipo, quindi immagino sia una versione della versione? Altre due cose che ho notato ormai: otherwisepossono sempre essere sostituite da 1<2(una scorciatoia per True), ma se ritorni a ifinvece puoi incorporare ee rilasciare tutti i nomi. E persino trasforma la piega in a concatMap, cioè a (>>=). Non risparmia molto, ma almeno un po '. Potrebbe risolvere anche l'errore di tipo.
MarLinn,

0

Python 2, 78 byte

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

Più ben formattato:

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

0

SQF , 199 176

Utilizzando il formato funzione come file:

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

Chiama come "STRING" call NAME_OF_COMPILED_FUNCTION


0

PowerShell v2 +, 146 byte

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'

A lungo perché volevo mostrare un approccio diverso piuttosto che semplicemente copiare e incollare la stessa stringa regex che tutti gli altri usano.

Invece qui, eseguiamo il ciclo di tutti i punti di codice che devono essere codificati in percentuale e facciamo un letterale -replacesulla stringa di input $nogni iterazione (salvando nuovamente in $n). Quindi dobbiamo tenere conto dei due caratteri speciali che devono essere evasi,\ e ^, quindi, questi sono in -replaceelementi separati alla fine. Dato che non abbiamo salvato nuovamente quella stringa finale, è rimasta sulla pipeline e la stampa è implicita.


0

Assembly x86 a 16/32 bit, 73 byte

Codice byte:

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

Smontaggio:

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

Chiama con:
- esi = puntatore al buffer che contiene la stringa di origine;
- edi = puntatore al buffer che riceve una stringa codificata;
- ecx = lunghezza della stringa di origine.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.