Phần trăm mã hóa một chuỗi


13

Giới thiệu

Như một số bạn có thể biết, URL thực sự có một danh sách các ký tự làm những việc đặc biệt. Ví dụ, /nhân vật tách các phần của URL, và ?, &=các nhân vật được sử dụng để vượt qua truy vấn các thông số đến máy chủ. Trong thực tế, có một loạt các nhân vật có chức năng đặc biệt : $&+,/:;=?@. Khi bạn cần sử dụng các ký tự này trong URL vì bất kỳ lý do nào khác ngoài các hàm đặc biệt, bạn phải thực hiện một thứ gọi là mã hóa phần trăm .

Mã hóa phần trăm là khi bạn lấy giá trị thập lục phân của một ký tự và thêm một %ký tự vào đầu của ký tự đó. Ví dụ, ký tự ?sẽ được mã hóa thành %3Fvà ký tự &sẽ được mã hóa thành %26. Trong một URL cụ thể, điều này cho phép bạn gửi các ký tự này dưới dạng dữ liệu qua URL mà không gây ra sự cố phân tích cú pháp. Thử thách của bạn sẽ là lấy một chuỗi và mã hóa phần trăm tất cả các ký tự cần được mã hóa.

Các thách thức

Bạn sẽ viết một chương trình hoặc hàm lấy trong một chuỗi gồm các ký tự có mã số 00-FF (ký tự ASCII và ASCII mở rộng). Sau đó, bạn sẽ phải xuất hoặc trả lại cùng một chuỗi với mỗi ký tự được mã hóa phần trăm nếu cần thiết. Xây dựng hoàn thành nhiệm vụ này là không được phép, cũng không phải là sơ hở tiêu chuẩn. Để tham khảo, đây là danh sách mọi ký tự cần được mã hóa phần trăm:

  • Kiểm soát các ký tự (Codepoints 00-1F và 7F)
  • Các ký tự ASCII mở rộng (Codepoints 80-FF)
  • Các ký tự dành riêng ( $&+,/:;=?@, tức là các điểm mã 24, 26, 2B, 2C, 2F, 3A, 3B, 3D, 3F, 40)
  • Các ký tự không an toàn ( " <>#%{}|\^~[]`ví dụ: mã hóa 20, 22, 3C, 3E, 23, 25, 7B, 7D, 7C, 5C, 5E, 7E, 5B, 5D, 60)

Đây là cùng một danh sách, nhưng thay vào đó là một danh sách các mã số thập phân:

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

Đây là mã golf, vì vậy mã ngắn nhất tính bằng byte (hoặc phương pháp tính điểm thay thế được phê duyệt) sẽ thắng!

Các trường hợp thử nghiệm

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

Bạn sẽ có một testcase hiển thị các ký tự điều khiển?
Nữ tu bị rò rỉ

@LeakyNun xong.
GamrCorps

Tôi chắc chắn rằng mật mã EFkhông chứa dấu hỏi.
dùng48538

@ zyabin101 bạn đã tìm thấy điều đó ở đâu? Tôi không nhìn thấy nó.
GamrCorps

"Ví dụ: ký tự? Sẽ được mã hóa thành% EF ..."
user48538

Câu trả lời:


2

Bình thường, 30 28 26 byte

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

thử trực tuyến

Giải trình

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.

CGthủ thuật này tạo ra một số lượng lớn có chứa tất cả các chữ số có thể. Điều này là hoàn hảo, vì chúng tôi không quan tâm đến các bản sao khi kiểm tra xem một chuỗi có nằm trong chuỗi khác không.


Câu trả lời này không đáp ứng được thông số kỹ thuật trong câu hỏi. Có nhiều nhân vật được phép hơn chỉ A-Za-z0-9. Ví dụ, .nên được bảo tồn hơn là dịch sang %2E. (cc: @GamrCorps)
DLosc

3

Vim, 67 byte / tổ hợp phím

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

Lưu ý <cr>đại diện cho khóa enter, ví dụ: 0x0Dmột byte đơn.

Đây là một giải pháp khá đơn giản. Giải trình:

: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)))Rác đó là vô duyêncùng .


" printf("%02x",char2nr(submatch(0)))Rác đó là vô duyên vô cùng" và cực kỳ hack
Leaky Nun

2

Perl, 40 byte

Mã 39 byte + -p.

Hơi khập khiễng, nhưng tôi nghĩ đó là giải pháp ngắn nhất ...

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

Sử dụng

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 byte

5 byte nhờ orlp.

1 byte nhờ Sp3000.

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

Nghĩa là nó!


re.match("[!'()*.0-9A-Za-z_-]",c)and c or'%%%02X'%ord(c)
orlp

@ Sp3000 \wbao gồm ASCII mở rộng
Leaky Nun

Ngoài ra, '()*->'-*
Sp3000

Tôi nghĩ rằng \whoạt động với tùy chọn 256( re.ASCII): ideone . Nó chắc chắn hoạt động trong Python 3 trên ideone và nó sẽ hoạt động với các u"..."chuỗi trong Python 2, nhưng ideone dường như làm những điều thú vị cho cái sau (ví dụ: print len(u"ÑÉÐÔ®")cho 10 trên ideone nhưng 5 trên repl.it và máy tính của tôi, mặc dù tất cả đều là 2.7. 10)
Sp3000

1

C, 83 byte

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

1

Python, 86 byte

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

Cổng C của tôi trả lời.


1

Ruby, 37 + 3 = 40 byte

Chạy với -p(3 byte thêm), như $ ruby -p percent_encode.rb:

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

1

Thạch , 28 27 byte

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

Đây là một liên kết đơn âm. Hãy thử trực tuyến!

Làm thế nào nó hoạt động

ḟØ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 byte

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

Ung dung:

import Data.Char
import Numeric

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

Bạn có thể loại bỏ một loạt các không gian?
Rɪᴋᴇʀ

Bạn có thể thả lỏng where, biến ifthành các vệ sĩ, biến e thành một phần, làm mất đi đối số cuối cùng showHex, nội tuyến p, nội tuyến s, mất chữ ký, sắp xếp lại elemvà mất nhiều khoảng trắng hơn. Như một xấp xỉ đầu tiên, tôi đã xuống tới 118 theo cách đó.
MarLinn

Cảm ơn @MarLinn vì một loạt các đề xuất tốt về việc cắt giảm mã. Tuy nhiên, tôi đã gặp một số rắc rối với những gợi ý nhất định. Trước hết, nếu tôi xóa chữ ký, GHC sẽ khiếu nại điều đó No instance for (Foldable t0) arising from a use of ‘foldr’. Nó nói rằng loại hàm này không rõ ràng, dẫn đến một ràng buộc được suy ra f :: t0 Char -> [Char]. Và thứ hai, tôi không thể xóa đối số chuỗi rỗng khỏi showHex vì nó trả về ShowS, đây là một bí danh loại String -> Stringdo đó cần chuỗi rỗng.
sham1

@ sham1, vâng, ShowSlấy Chuỗi ... nhưng bạn có một: chuỗi bạn đang thêm (++). Vì vậy, bạn có thể mất cả hai cùng một lúc. Đó thực sự là lý do tại sao ShowStrông như vậy. Tôi không nhận được lỗi loại, vì vậy tôi đoán đó là một phiên bản? Hai điều khác tôi nhận thấy bây giờ: otherwiseluôn có thể được thay thế bằng 1<2(một cách viết tắt True), nhưng nếu bạn quay lại ifthay vào đó bạn có thể nội tuyến evà bỏ tất cả các tên. Và thậm chí biến nếp gấp thành a concatMap, tức là a (>>=). Không tiết kiệm nhiều, nhưng ít nhất một chút. Cũng có thể giải quyết lỗi loại.
MarLinn

0

Python 2, 78 byte

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

Định dạng độc đáo hơn:

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

0

SQF , 199 176

Sử dụng định dạng hàm dưới dạng tệp:

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

Gọi như "STRING" call NAME_OF_COMPILED_FUNCTION


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'

Lâu bởi vì tôi muốn hiển thị một cách tiếp cận khác thay vì chỉ sao chép dán cùng một chuỗi regex mà mọi người khác đang sử dụng.

Thay vào đó, chúng tôi lặp qua mọi điểm mã phải được mã hóa theo phần trăm và thực hiện một ký tự -replacetrên chuỗi đầu vào $nmỗi lần lặp (lưu lại vào $n). Sau đó, chúng ta cần tính đến hai ký tự đặc biệt cần thoát, \^, vì vậy chúng nằm trong các -replacephần tử riêng biệt ở cuối. Vì chúng tôi đã không lưu lại chuỗi cuối cùng đó, nên nó nằm trên đường ống dẫn và việc in ấn hoàn toàn ẩn.


0

Lắp ráp x86 16/32-bit, 73 byte

Mã 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

Tháo gỡ:

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

Gọi bằng:
- esi = con trỏ tới bộ đệm chứa chuỗi nguồn;
- edi = con trỏ tới bộ đệm nhận chuỗi được mã hóa;
- ecx = chiều dài của chuỗi nguồn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.