Persen-Encode sebuah String

13

pengantar

Seperti yang mungkin Anda ketahui, URL sebenarnya memiliki daftar karakter yang melakukan hal-hal khusus. Sebagai contoh, /karakter memisahkan bagian-bagian dari URL, dan ?, &, dan =karakter yang digunakan untuk melewati permintaan parameter ke server. Bahkan, ada sekelompok karakter dengan fungsi khusus: $&+,/:;=?@. Ketika Anda perlu menggunakan karakter ini di URL untuk alasan lain selain fungsi khusus, Anda harus melakukan sesuatu yang disebut pengodean persen .

Persen pengkodean adalah ketika Anda mengambil nilai heksadesimal karakter dan menambahkan %karakter ke awal. Misalnya, karakter ?akan dikodekan sebagai %3F, dan karakter &akan dikodekan sebagai %26. Di URL secara khusus, ini memungkinkan Anda untuk mengirim karakter ini sebagai data melalui URL tanpa menyebabkan masalah penguraian. Tantangan Anda adalah mengambil string, dan meng-enkode semua karakter yang perlu dikodekan.

Tantangan

Anda harus menulis program atau fungsi yang menggunakan string tunggal yang terdiri dari karakter dengan codepoint 00-FF (karakter ASCII dan Extended ASCII). Anda kemudian harus menampilkan atau mengembalikan string yang sama dengan setiap karakter persen-disandikan jika perlu. Built-in yang menyelesaikan tugas ini tidak diperbolehkan, juga tidak ada celah standar. Untuk referensi, berikut adalah daftar setiap karakter yang perlu dikodekan persen:

  • Kontrol karakter (Codepoints 00-1F dan 7F)
  • Karakter ASCII yang diperluas (Codepoints 80-FF)
  • Karakter yang dicadangkan ( $&+,/:;=?@, yaitu titik kode 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • Karakter tidak aman ( " <>#%{}|\^~[]`, yaitu titik kode 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

Berikut ini adalah daftar yang sama, tetapi sebagai daftar dari codepoint desimal:

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

Ini golf kode, jadi kode terpendek dalam byte (atau metode penilaian alternatif yang disetujui) menang!

Uji Kasus

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
sumber
Apakah Anda memiliki testcase yang menunjukkan karakter kontrol?
Leaky Nun
@ LeakyNun selesai.
GamrCorps
Saya yakin codepoint EFtidak mengandung tanda tanya.
user48538
@ zyabin101 di mana Anda menemukan itu? Saya tidak melihatnya.
GamrCorps
"Misalnya, karakter? Akan dikodekan sebagai% EF ..."
user48538

Jawaban:

2

Pyth, 30 28 26 byte

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

coba online

Penjelasan

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.

CGadalah trik ini yang menghasilkan sejumlah besar yang berisi semua kemungkinan angka. Ini sempurna, karena kami tidak peduli dengan duplikat ketika memeriksa apakah string ada di string lain.

Lars
sumber
Jawaban ini tidak memenuhi spesifikasi dalam pertanyaan. Ada lebih banyak karakter yang diizinkan dari sekadar A-Za-z0-9. Misalnya, .harus dilestarikan daripada diterjemahkan %2E. (cc: @GamrCorps)
DLosc
3

Vim, 67 byte / penekanan tombol

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

Catatan yang <cr>mewakili tombol enter, misalnya 0x0Dyang merupakan byte tunggal.

Ini adalah solusi yang cukup mudah. Penjelasan:

: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

Itu printf("%02x",char2nr(submatch(0)))sampah sangat ungolfy .

James
sumber
" printf("%02x",char2nr(submatch(0)))Sampah itu sangat ungolfy" dan sangat pekat
Leaky Nun
2

Perl, 40 byte

39 byte kode + -p.

Agak timpang, tapi saya pikir itu solusi terpendek ...

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

Pemakaian

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
sumber
2

Julia, 47 byte

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

Cobalah online!

Dennis
sumber
1

Python 3, 92 byte

5 byte berkat orlp.

1 byte berkat Sp3000.

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

Ide itu!

Biarawati Bocor
sumber
re.match("[!'()*.0-9A-Za-z_-]",c)and c or'%%%02X'%ord(c)
orlp
@ Sp3000 \wtermasuk ASCII diperpanjang
Leaky Nun
Juga, '()*->'-*
Sp3000
Saya pikir \wbekerja dengan opsi 256( re.ASCII): ideone . Ini pasti bekerja di Python 3 pada ideone, dan itu harus bekerja dengan u"..."string di Python 2, tetapi ideone tampaknya melakukan hal-hal yang funky untuk yang terakhir (misalnya print len(u"ÑÉÐÔ®")memberikan 10 pada ideone tetapi 5 pada repl.it dan komputer saya, meskipun semuanya 2.7. 10)
Sp3000
1

C, 83 byte

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

Python, 86 byte

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

Port jawaban C saya.

orlp
sumber
1

Ruby, 37 + 3 = 40 byte

Jalankan dengan -p(3 byte tambahan), seperti $ ruby -p percent_encode.rb:

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

Jelly , 28 27 byte

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

Ini adalah tautan monadik. Cobalah online!

Bagaimana itu bekerja

ḟØ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
sumber
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)"")

Tidak Disatukan:

import Data.Char
import Numeric

f=(=<<) e
e c = if isAlphaNum c && isAscii c && c `elem` "-_.~" then [c] else '%' : (showHex $ ord c) ""
sham1
sumber
Bisakah Anda menghapus banyak ruang?
Rɪᴋᴇʀ
Anda dapat kehilangan where, mengubah ifpenjaga menjadi, membuat sebagian, kehilangan argumen terakhir dari showHex, inline p, inline s, kehilangan tanda tangan, menyusun ulang elemdan kehilangan lebih banyak spasi. Sebagai perkiraan pertama saya turun ke 118 dengan cara itu.
MarLinn
Terima kasih @MarLinn untuk banyak saran bagus untuk memangkas kode. Namun, saya punya beberapa masalah dengan saran-saran tertentu. Pertama-tama, jika saya menghapus tanda tangan, GHC akan mengeluh itu No instance for (Foldable t0) arising from a use of ‘foldr’. Dikatakan bahwa jenis fungsinya ambigu, menghasilkan pengikatan yang disimpulkan f :: t0 Char -> [Char]. Dan yang kedua, saya tidak bisa menghapus argumen string kosong dari showHex karena mengembalikan ShowS, yang merupakan jenis alias karena String -> Stringitu membutuhkan string kosong.
sham1
@ sham1, ya, ShowSmengambil sebuah String ... tetapi Anda memiliki satu: yang Anda tambahkan (++). Jadi, Anda bisa kehilangan keduanya sekaligus. Itulah sebabnya mengapa ShowSterlihat seperti itu. Saya tidak mendapatkan kesalahan ketik, jadi saya kira ini versi versi? Dua hal lain yang saya perhatikan sekarang: otherwiseselalu dapat digantikan oleh 1<2(singkatan untuk True), tetapi jika Anda kembali ke ifsebaliknya Anda dapat inline edan letakkan semua nama. Dan bahkan mengubah lipatan menjadi concatMap, yaitu a (>>=). Tidak banyak menabung, tapi setidaknya sedikit. Mungkin bisa mengatasi kesalahan tipe juga.
MarLinn
0

Python 2, 78 byte

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

Lebih baik diformat:

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

SQF , 199 176

Menggunakan format fungsi-sebagai-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

Sebut sebagai "STRING" call NAME_OF_COMPILED_FUNCTION

Suram
sumber
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'

Lama karena saya ingin menunjukkan pendekatan yang berbeda daripada hanya menyalin-menempel string regex yang sama yang digunakan orang lain.

Alih-alih di sini, kita mengulangi setiap titik kode yang harus dikodekan persen, dan melakukan literal -replacepada string input $nsetiap iterasi (menyimpan kembali ke dalam $n). Maka kita perlu memperhitungkan dua karakter khusus yang perlu melarikan diri, \dan ^, jadi itu adalah -replaceelemen yang terpisah di akhir. Karena kami tidak menyimpan ulang string terakhir, itu masih ada di jalur pipa dan pencetakan tersirat.

AdmBorkBork
sumber
0

Perakitan x86 16/32-bit, 73 byte

Kode 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

Membongkar:

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

Panggil dengan:
- esi = pointer ke buffer yang menampung string sumber;
- edi = pointer ke buffer yang menerima string yang disandikan;
- ecx = panjang string sumber.

Peter Ferrie
sumber