Процент-кодування рядка


14

Вступ

Як деякі з вас можуть знати, 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, 3С, 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

Чи є у вас контрольна скринька, на якій зображені контрольні символи?
Leaky Nun

@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це такий трюк , які генерують величезну кількість , яке містить всі можливі цифри. Це ідеально, оскільки ми не піклуємось про дублікати, перевіряючи, чи є рядок в іншій.


Ця відповідь не відповідає специфікації у питанні. Дозволених персонажів більше, ніж просто 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

Пітон 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
Leaky Nun

Також, '()*->'-*
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);}

1

Пітон, 86 байт

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

Порт моєї відповіді на С.


1

Ruby, 37 + 3 = 40 байт

Запустити -p(3 додаткові байти), наприклад $ ruby -p percent_encode.rb:

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

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)"")

Безголівки:

import Data.Char
import Numeric

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

Чи можете ви видалити купу пробілів?
Rɪᴋᴇʀ

Ви можете втратити where, перетворити ifна гвардії, зробити частковим, втратити останній аргумент showHex, вбудований p, рядковий s, втратити підпис, змінити порядок elemі втратити ще більше пробілів. Як перше наближення я таким чином зійшов до 118.
MarLinn

Дякую @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всі рядки та залишити їх. І навіть перетворіть складку на a concatMap, тобто a (>>=). Це не економить багато, але хоча б трохи. Може також вирішити помилку типу.
MarLinn

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)

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


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елементах наприкінці. Оскільки ми не зберегли цей остаточний рядок, він залишається на конвеєрі, а друк неявний.


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 = довжина вихідного рядка.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.