Процент-кодирование строки

13

Вступление

Как некоторые из вас могут знать, URL-адреса на самом деле имеют список символов, которые делают особые вещи. Например, /символ отделяет части URL, и ?, &и =символы используются для передачи запроса параметров на сервер. В самом деле, есть куча символов с помощью специальных функций: $&+,/:;=?@. Когда вам нужно использовать эти символы в URL-адресе по любой другой причине, кроме специальных функций, вы должны выполнить то, что называется процентным кодированием .

Процент кодирования - это когда вы берете шестнадцатеричное значение %символа и добавляете символ к его началу. Например, символ ?будет закодирован как %3F, а символ &закодирован как %26. В частности, в URL-адресе это позволяет отправлять эти символы в виде данных через URL-адрес, не вызывая проблем с анализом. Ваша задача - взять строку и кодировать в процентах все символы, которые необходимо кодировать.

Соревнование

Вы должны написать программу или функцию, которая принимает одну строку, состоящую из символов с кодовыми точками 00-FF (символы ASCII и Extended ASCII). Затем вам необходимо будет вывести или вернуть одну и ту же строку с каждым символом, закодированным в процентах, если это необходимо. Встроенные модули, которые выполняют эту задачу, не допускаются, как и стандартные лазейки. Для справки, вот список каждого символа, который должен быть в процентах:

  • Управляющие символы (кодовые точки 00-1F и 7F)
  • Расширенные символы ASCII (кодовые точки 80-FF)
  • Зарезервированные символы ( $&+,/:;=?@т. Е. Кодовые точки 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • Небезопасные символы ( " <>#%{}|\^~[]`т. Е. Кодовые точки 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

Вот тот же список, но вместо этого как список десятичных кодовых точек:

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

Это кодовый гольф, поэтому выигрывает самый короткий код в байтах (или одобренный альтернативный метод подсчета очков)!

Тестовые случаи

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
источник
Будет ли у вас тест-кейс, показывающий управляющие символы?
Утренняя монахиня
@ LeakyNun сделано.
GamrCorps
Я уверен, что кодовая точка EFне содержит вопросительный знак.
user48538
@ zyabin101 где ты это нашел? Я не вижу этого.
GamrCorps
«Например, символ? Будет закодирован как% EF ...»
user48538

Ответы:

2

Pyth, 30 28 26 байт

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

попробуйте это онлайн

объяснение

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 является такой трюк , которые генерируют огромное количество , которое содержит все возможные цифры. Это прекрасно, так как нам не нужны дубликаты при проверке, находится ли строка в другой.

Lars
источник
Этот ответ не соответствует спецификации в вопросе. Есть больше разрешенных символов, чем просто A-Za-z0-9. Например, .должен быть сохранен, а не переведен в %2E. (cc: @GamrCorps)
DLosc
3

Vim, 67 байт / нажатий клавиш

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

Обратите внимание, что <cr>представляет ключ ввода, например, 0x0Dкоторый является одним байтом.

Это довольно простое решение. Объяснение:

: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

Этот printf("%02x",char2nr(submatch(0)))мусор ужасно негольфителен .

Джеймс
источник
«Этот printf("%02x",char2nr(submatch(0)))мусор ужасно нечистоплотный» и чрезвычайно хакерский
Leaky Nun
2

Perl, 40 байт

39 байт код + -p .

Немного отстой, но я думаю, что это самое короткое решение ...

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

использование

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 байта

5 байт благодаря orlp.

1 байт благодаря Sp3000.

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

Идео это!

Дрянная Монахиня
источник
re.match("[!'()*.0-9A-Za-z_-]",c)and c or'%%%02X'%ord(c)
orlp
@ Sp3000 \wвключает расширенный ASCII
Утренняя монахиня
Кроме того, '()*->'-*
Sp3000
Я думаю, что \wработает с опцией 256( re.ASCII): Ideone . Он определенно работает в Python 3 на ideone, и он должен работать со u"..."строками в Python 2, но ideone, кажется, делает что-то необычное с последним (например, print len(u"ÑÉÐÔ®")дает 10 на ideone, но 5 на repl.it и моем компьютере, несмотря на то, что все равно 2.7. 10)
Sp3000
1

C 83 байта

f(char*p){for(;*p;++p)printf(isalnum(*p)||strchr("!'()*-._",*p)?"%c":"%%%02X",*p);}
orlp
источник
1

Python, 86 байт

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

Порт моего C ответа.

orlp
источник
1

Рубин, 37 + 3 = 40 байт

Выполнить с -p(3 дополнительных байта), например $ ruby -p percent_encode.rb:

gsub(/[^\w!'()*-.]/){"%%%02X"%$&.ord}
daniero
источник
1

Желе , 28 27 байт

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

Это монадическая ссылка. Попробуйте онлайн!

Как это устроено

ḟØ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 байт

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) ""
sham1
источник
Можете ли вы удалить кучу пробелов?
Rɪᴋᴇʀ
Вы можете потерять where, превратить ifв охранников, сделать частичным, потерять последний аргумент showHex, встроенный p, встроенный s, потерять подпись, изменить порядок elemи потерять еще больше пробелов. В первом приближении я опустился до 118 таким образом.
Марлинн
Спасибо @MarLinn за кучу хороших предложений по урезанию кода. Однако у меня были некоторые проблемы с некоторыми предложениями. Прежде всего, если я удалю подпись, GHC будет жаловаться на это No instance for (Foldable t0) arising from a use of ‘foldr’. Это говорит о том, что тип функции неоднозначен, что приводит к предполагаемому связыванию f :: t0 Char -> [Char]. И, во-вторых, я не смог удалить аргумент пустой строки из showHex, так как он возвращает ShowS, который является псевдонимом типа для String -> Stringтакой необходимости пустой строки.
sham1
@ sham1, да, ShowSпринимает строку ... но у вас есть одна: та, с которой вы добавляете (++). Таким образом, вы можете потерять оба одновременно. Вот почему на самом деле ShowSвыглядит именно так. Я не получаю ошибку типа, так что я думаю, что это версия версии? К настоящему времени я заметил еще две вещи: otherwiseвсегда можно заменить на 1<2(сокращение True), но если вы вернетесь ifвместо этого, вы можете вставить eи удалить все имена. И даже превратить створку в concatMap, т.е. (>>=). Не много экономит, но хоть немного. Может решить и ошибку типа тоже.
Марлинн
0

Python 2, 78 байт

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

Более красиво отформатирован:

lambda s:
    "".join(["%%%02x" % ord(c), c][c.isalnum() or c in"!'()*-._"] for c in s)
Byte Commander
источник
0

SQF , 199 176

Использование формата «функция как файл»:

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

Позвонить как "STRING" call NAME_OF_COMPILED_FUNCTION

Οurous
источник
0

PowerShell v2 +, 146 байт

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'

Долго, потому что я хотел показать другой подход, а не просто копировать и вставлять ту же строку регулярного выражения, которую используют все остальные.

Вместо этого здесь мы перебираем каждую кодовую точку, которая должна кодироваться в процентах, и делаем литерал -replaceдля входной строки $nкаждую итерацию (повторное сохранение обратно в $n). Затем нам нужно учесть два специальных символа, которые нужно экранировать, \и ^, таким образом, они находятся в отдельных -replaceэлементах в конце. Поскольку мы не сохранили эту последнюю строку, она остается в конвейере, и печать неявна.

AdmBorkBork
источник
0

16/32-битная сборка x86, 73 байта

Байт-код:

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

Разборка:

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

Вызов с:
- esi = указатель на буфер, который содержит исходную строку;
- edi = указатель на буфер, который получает закодированную строку;
- ecx = длина исходной строки.

Питер Ферри
источник