百分比编码字符串


14

介绍

如您中某些人所知,URL实际上具有执行特殊功能的字符列表。例如,/字符分开的网址的部分,并且?&=字符用于查询参数传递给服务器。实际上,有一堆具有特殊功能的字符:$&+,/:;=?@。除了特殊功能之外,如果出于其他任何原因需要在URL中使用这些字符,则必须执行称为percent-encoding的操作

百分比编码是当您采用字符的十六进制值并将%字符放在字符开头时。例如,字符?将被编码为%3F,字符&将被编码为%26。特别是在URL中,这使您可以通过URL将这些字符作为数据发送,而不会引起解析问题。您的挑战将是获取一个字符串,并对所有需要编码的字符进行百分比编码。

挑战

您应该编写一个程序或函数,该程序或函数采用单个字符串,该字符串由代码点为00-FF的字符(ASCII和扩展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

您将有一个显示控制字符的测试用例吗?
Leaky Nun

@LeakyNun完成。
GamrCorps,2016年

我确定codepoint EF不包含问号。
user48538 '16

@ zyabin101您在哪里找到的?我没有看到它。
GamrCorps,2016年

“例如,字符?将被编码为%EF ...”
user48538,2013年

Answers:


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。(抄送:@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)))垃圾是非常ungolfy”和极其哈克
漏尼姑

2

Perl,40个字节

39字节代码+ -p

有点la脚,但我认为这是最短的解决方案...

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
Leaky Nun

此外,'()*->'-*
Sp3000

我认为\w可以使用256re.ASCII)选项:ideone。它肯定可以在ideone上的Python 3中工作,并且应该可以u"..."在Python 2中与字符串一起工作,但是ideone似乎可以对后者做些时髦的事情(例如print len(u"ÑÉÐÔ®"),在ideone上给10,在repl.it和我的计算机上给5 ,尽管所有都是2.7。 10)
Sp3000

1

C,83字节

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

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

这是一个单子链接。在线尝试!

怎么运行的

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

哈斯克尔, 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变成防护,使e部分化,松开showHex,inline p,inline 的最后一个参数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 '16

@ sham1,是的,ShowS需要一个String ...但是您有一个:您要添加的字符串(++)。因此,您可以同时松开两者。这就是为什么这样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

SQF199 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 =源字符串的长度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.