Encoder en pourcentage une chaîne

13

introduction

Comme certains d'entre vous le savent peut-être, les URL ont en fait une liste de caractères qui font des choses spéciales. Par exemple, le /caractère sépare les parties de l'URL, et ?, &et les =caractères sont utilisés pour passer des paramètres de requête au serveur. En fait, il y a un tas de personnages avec des fonctions spéciales: $&+,/:;=?@. Lorsque vous devez utiliser ces caractères dans l'URL pour toute autre raison que les fonctions spéciales, vous devez faire quelque chose appelé encodage en pourcentage .

L'encodage en pourcentage consiste à prendre la valeur hexadécimale d'un %caractère et à ajouter un caractère au début de celui-ci. Par exemple, le caractère ?serait codé comme %3Fet le caractère &serait codé comme %26. Dans une URL en particulier, cela vous permet d'envoyer ces caractères sous forme de données via l'URL sans provoquer de problèmes d'analyse. Votre défi sera de prendre une chaîne et de coder en pourcentage tous les caractères qui doivent être codés.

Le défi

Vous devez écrire un programme ou une fonction qui accepte une seule chaîne composée de caractères avec des points de code 00-FF (caractères ASCII et ASCII étendus). Vous devrez ensuite générer ou renvoyer la même chaîne avec chaque caractère codé en pourcentage si nécessaire. Les fonctions intégrées qui accomplissent cette tâche ne sont pas autorisées, pas plus que les failles standard. Pour référence, voici une liste de chaque caractère qui doit être encodé en pourcentage:

  • Caractères de contrôle (Codepoints 00-1F et 7F)
  • Caractères ASCII étendus (Codepoints 80-FF)
  • Caractères réservés ( $&+,/:;=?@c'est-à-dire les points de code 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • Caractères dangereux ( " <>#%{}|\^~[]`c'est-à-dire les points de code 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

Voici la même liste, mais à la place comme une liste de points de code décimaux:

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

C'est le golf de code, donc le code le plus court en octets (ou la méthode de notation alternative approuvée) gagne!

Cas de 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
GamrCorps
la source
Auriez-vous un testcase qui montre les caractères de contrôle?
Leaky Nun
@LeakyNun fait.
GamrCorps
Je suis sûr que le point de code EFne contient pas le point d'interrogation.
user48538
@ zyabin101 où avez-vous trouvé cela? Je ne le vois pas.
GamrCorps
"Par exemple, le caractère? Serait encodé en% EF ..."
user48538

Réponses:

2

Pyth, 30 28 26 octets

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

essayez-le en ligne

Explication

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.

CGest cette astuce qui génère un nombre énorme qui contient tous les chiffres possibles. C'est parfait, car nous ne nous soucions pas des doublons lorsque nous vérifions si une chaîne se trouve dans une autre.

Lars
la source
Cette réponse ne correspond pas aux spécifications de la question. Il y a plus de caractères autorisés que juste A-Za-z0-9. Par exemple, .doit être conservé plutôt que traduit en %2E. (cc: @GamrCorps)
DLosc
3

Vim, 67 octets / frappes

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

Notez que cela <cr>représente la touche Entrée, par exemple 0x0Dqui est un seul octet.

Il s'agit d'une solution assez simple. Explication:

: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

Ces printf("%02x",char2nr(submatch(0)))ordures sont terriblement impies .

James
la source
"Ces printf("%02x",char2nr(submatch(0)))ordures sont terriblement impies" et extrêmement hacky
Leaky Nun
2

Perl, 40 octets

Code de 39 octets + -p.

Un peu boiteux, mais je pense que c'est la solution la plus courte ...

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

Usage

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
la source
2

Julia, 47 octets

!s=replace(s,r"[^\w!'()*.-]",c->"%"hex(c[1],2))

Essayez-le en ligne!

Dennis
la source
1

Python 3, 92 octets

5 octets grâce à orlp.

1 octet grâce au 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!

Leaky Nun
la source
re.match("[!'()*.0-9A-Za-z_-]",c)and c or'%%%02X'%ord(c)
orlp
@ Sp3000 \winclut ASCII étendu
Leaky Nun
Aussi, '()*->'-*
Sp3000
Je pense que cela \wfonctionne avec l' option 256( re.ASCII): ideone . Cela fonctionne certainement en Python 3 sur ideone, et cela devrait fonctionner avec des u"..."chaînes en Python 2, mais ideone semble faire des choses amusantes à ce dernier (par exemple print len(u"ÑÉÐÔ®")donne 10 sur ideone mais 5 sur repl.it et mon ordinateur, bien que tous soient 2.7. 10)
Sp3000
1

C, 83 octets

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

Python, 86 octets

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

Port de ma réponse C.

orlp
la source
1

Ruby, 37 + 3 = 40 octets

Exécutez avec -p(3 octets supplémentaires), comme $ ruby -p percent_encode.rb:

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

Gelée , 28 27 octets

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

Ceci est un lien monadique. Essayez-le en ligne!

Comment ça fonctionne

ḟØ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
la source
1

Haskell, 201 179 178 127 119 octets

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

Non golfé:

import Data.Char
import Numeric

f=(=<<) e
e c = if isAlphaNum c && isAscii c && c `elem` "-_.~" then [c] else '%' : (showHex $ ord c) ""
sham1
la source
Pouvez-vous supprimer un tas d'espaces?
Rɪᴋᴇʀ
Vous pouvez perdre le where, transformer le ifen gardes, rendre partiel, perdre le dernier argument de showHex, en ligne p, en ligne s, perdre la signature, réorganiser le elemet perdre encore plus d'espace. En première approximation, je suis descendu à 118 de cette façon.
MarLinn
Merci @MarLinn pour un tas de bonnes suggestions sur la réduction du code. Cependant, j'ai eu quelques problèmes avec certaines suggestions. Tout d'abord, si je retire la signature, GHC s'en plaindra No instance for (Foldable t0) arising from a use of ‘foldr’. Il dit que le type de la fonction est ambigu, ce qui entraîne une liaison inférée de f :: t0 Char -> [Char]. Et deuxièmement, je n'ai pas pu supprimer l'argument de chaîne vide de showHex car il renvoie un ShowS, qui est un alias de type pour String -> Stringavoir donc besoin de la chaîne vide.
sham1
@ sham1, oui, ShowSprend une chaîne ... mais vous en avez une: celle avec laquelle vous ajoutez (++). Vous pouvez donc perdre les deux en même temps. C'est en fait pourquoi ShowSça ressemble à ça. Je ne reçois pas l'erreur de type, donc je suppose que c'est une chose de version? Deux autres choses que j'ai remarquées maintenant: otherwisepeuvent toujours être remplacées par 1<2(un raccourci pour True), mais si vous revenez à la ifplace, vous pouvez incorporer eet supprimer tous les noms. Et même transformer le pli en a concatMap, c'est-à-dire a (>>=). N'économise pas beaucoup, mais au moins un peu. Pourrait également résoudre l'erreur de type.
MarLinn
0

Python 2, 78 octets

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

Plus joliment formaté:

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

SQF , 199 176

Utilisation du format de fonction en tant que fichier:

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

Appelez en tant que "STRING" call NAME_OF_COMPILED_FUNCTION

Οurous
la source
0

PowerShell v2 +, 146 octets

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'

Long parce que je voulais montrer une approche différente plutôt que de simplement copier-coller la même chaîne d'expression régulière que tout le monde utilise.

Au lieu de cela ici, nous parcourons chaque point de code qui doit être codé en pourcentage, et faisons un littéral -replacesur la chaîne d'entrée à $nchaque itération (réenregistrant dans $n). Ensuite, nous devons prendre en compte les deux caractères spéciaux qui doivent être échappés, \et ^donc ils se trouvent dans des -replaceéléments séparés à la fin. Comme nous n'avons pas réenregistré cette chaîne finale, elle est laissée dans le pipeline et l'impression est implicite.

AdmBorkBork
la source
0

Assemblage x86 16/32 bits, 73 octets

Code d'octet:

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

Démontage:

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

Appeler avec:
- esi = pointeur vers le tampon contenant la chaîne source;
- edi = pointeur vers le tampon qui reçoit la chaîne codée;
- ecx = longueur de la chaîne source.

peter ferrie
la source