ร้อยละเข้ารหัสสตริง


14

บทนำ

อย่างที่คุณบางคนอาจทราบ URL มีรายการอักขระที่ทำสิ่งพิเศษ ยกตัวอย่างเช่น/ตัวอักษรแยกชิ้นส่วนของ URL และ?, &และ=ตัวอักษรที่ใช้ในการส่งผ่านพารามิเตอร์แบบสอบถามไปยังเซิร์ฟเวอร์ อันที่จริงมีตัวละครมากมายที่มีฟังก์ชั่นพิเศษ: $&+,/:;=?@. เมื่อคุณจำเป็นต้องใช้ตัวอักษรเหล่านี้ใน URL สำหรับเหตุผลอื่นใดนอกเหนือจากฟังก์ชั่นพิเศษที่คุณต้องทำสิ่งที่เรียกว่าการเข้ารหัสเปอร์เซ็นต์

การเข้ารหัสเป็นเปอร์เซ็นต์คือเมื่อคุณใช้ค่าเลขฐานสิบหกของตัวละครและเติม%อักขระไปที่จุดเริ่มต้นของอักขระ ยกตัวอย่างเช่นตัวละคร?จะถูกเข้ารหัสเป็น%3Fและตัวละครจะถูกเข้ารหัสเป็น& %26ใน URL โดยเฉพาะสิ่งนี้จะช่วยให้คุณสามารถส่งอักขระเหล่านี้เป็นข้อมูลผ่าน URL โดยไม่ทำให้เกิดปัญหาในการแยกวิเคราะห์ ความท้าทายของคุณคือการใช้สายอักขระและเข้ารหัสเปอร์เซ็นต์อักขระทั้งหมดที่จำเป็นต้องเข้ารหัส

ความท้าทาย

คุณจะต้องเขียนโปรแกรมหรือฟังก์ชั่นที่ใช้ในสายอักขระเดียวซึ่งประกอบด้วยอักขระที่มี codepoints 00-FF (ASCII และอักขระ ASCII เพิ่มเติม) จากนั้นคุณจะต้องส่งออกหรือส่งกลับสตริงเดียวกันโดยมีการเข้ารหัสเปอร์เซ็นต์อักขระแต่ละตัวหากจำเป็น บิวด์อินที่ทำให้งานนี้สำเร็จไม่ได้รับอนุญาตและไม่เป็นช่องโหว่มาตรฐาน สำหรับการอ้างอิงนี่คือรายการของตัวละครทุกตัวที่ต้องเข้ารหัสเป็นเปอร์เซ็นต์:

  • อักขระควบคุม (Codepoints 00-1F และ 7F)
  • อักขระ ASCII เพิ่มเติม (Codepoints 80-FF)
  • อักขระที่จองไว้ ( $&+,/:;=?@เช่น codepoints 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • อักขระที่ไม่ปลอดภัย ( " <>#%{}|\^~[]`เช่น codepoints 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

นี่คือรายการเดียวกัน แต่เป็นรายการของ codepoints ทศนิยม:

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

คุณจะมี testcase ที่แสดงตัวควบคุมหรือไม่
Leun Nun

@LeakyNun เสร็จแล้ว
GamrCorps

ฉันแน่ใจว่า codepoint 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

เป็นกลุ่ม 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)))ขยะเป็นชะมัดungolfy


" 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 แบบขยาย
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

Python ขนาด 86 ไบต์

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

พอร์ตของคำตอบ C ของฉัน


1

Ruby, 37 + 3 = 40 ไบต์

ทำงานด้วย-p(3 ไบต์พิเศษ) เช่น$ ruby -p percent_encode.rb:

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

1

เยลลี่ , 28 27 ไบต์

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

นี่คือลิงค์ monadic ลองออนไลน์!

มันทำงานอย่างไร

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

คุณสามารถลบช่องว่างได้ไหม
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ยิง String ... แต่คุณมีหนึ่ง: (++)คนที่คุณกำลังเพิ่มด้วย ดังนั้นคุณสามารถหลวมทั้งสองในเวลาเดียวกัน นั่นเป็นเหตุผลว่าทำไมShowSหน้าตาแบบนั้น ฉันไม่ได้รับประเภทของข้อผิดพลาดดังนั้นฉันคิดว่ามันเป็นเวอร์ชั่น สองสิ่งอื่น ๆ ที่ฉันสังเกตเห็นในตอนนี้: otherwiseสามารถถูกแทนที่ด้วย1<2(ชวเลขสำหรับTrue) แต่ถ้าคุณกลับไปที่ifแทนคุณสามารถอินไลน์eและวางชื่อทั้งหมด และแม้กระทั่งการเปิดพับเป็นกล่าวคือconcatMap (>>=)ประหยัดไม่มาก แต่อย่างน้อยก็น้อย อาจแก้ข้อผิดพลาดประเภทได้เช่นกัน
MarLinn


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'

นานเพราะฉันต้องการที่จะแสดงวิธีการที่แตกต่างกันมากกว่าเพียงแค่คัดลอกวางสตริง Regex เดียวกันที่ทุกคนใช้

แต่ที่นี่เราวนซ้ำทุกจุดของรหัสที่ต้องมีการเข้ารหัสเป็นเปอร์เซ็นต์และทำตามตัวอักษร-replaceในสตริงอินพุต$nแต่ละการวนซ้ำ (บันทึกซ้ำอีกครั้ง$n) จากนั้นเราจำเป็นต้องพิจารณาตัวละครพิเศษสองตัวที่จำเป็นต้องหลบหนี\และ^ดังนั้นตัวละครเหล่านี้จึงแยกออกเป็น-replaceองค์ประกอบตอนท้าย เนื่องจากเราไม่ได้บันทึกสตริงสุดท้ายอีกครั้งจึงเหลืออยู่บนไปป์ไลน์และการพิมพ์มีความหมายโดยนัย


0

ชุดประกอบ x86 16/32 บิต 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 = ความยาวของสตริงต้นทาง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.