문자열 퍼센트 인코딩


14

소개

아시다시피 URL에는 실제로 특수한 작업을 수행하는 문자 목록이 있습니다. 예를 들어, /문자는 URL의 일부를 분리하고 ?, &그리고 =문자는 서버에 쿼리 매개 변수를 전달하는 데 사용됩니다. 실제로 특수 기능을 가진 많은 문자가 $&+,/:;=?@있습니다. 특수 함수 이외의 다른 이유로 URL에서 이러한 문자를 사용해야하는 경우 percent-encoding 을 수행해야합니다 .

퍼센트 인코딩은 문자의 16 진수 값을 가져 와서 문자 앞에 %시작하는 것입니다. 예를 들어, 문자 ?는로 인코딩되고 %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)

다음은 동일한 목록이지만 10 진수 코드 포인트 목록입니다.

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를 들어 단일 바이트 인 enter 키 를 나타냅니다 .

이것은 매우 간단한 해결책입니다. 설명:

: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

펄, 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 바이트

orlp 덕분에 5 바이트

Sp3000 덕분에 1 바이트

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를 포함
새는 수녀

또한, '()*->'-*
Sp3000

나는 ( ) 옵션으로 \w작동 한다고 생각 합니다 : ideone . 그것은 파이썬 3에서 ideone으로 확실히 작동하고 파이썬 2에서 문자열로 작동 해야 하지만, ideone은 후자에게 펑키 한 일을하는 것처럼 보입니다 (예 : ideone 에서는 10을 , repl.it 및 내 컴퓨터에서는 5를 제공합니다 . 모두 2.7 임에도 불구하고). 10)256re.ASCIIu"..."print len(u"ÑÉÐÔ®")
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)

내 C 답변의 포트.


1

루비, 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가드로 바꾸고, 부분적으로 만들고 showHex,, 인라인 p, 인라인 의 마지막 인수를 s풀고, 서명을 풀고, elem더 많은 공백을 풀 수 있습니다. 첫 번째 근사로 나는 118로 줄였습니다.
MarLinn

코드 다듬기에 대한 좋은 제안에 대해 @MarLinn에게 감사드립니다. 그러나 특정 제안에 문제가있었습니다. 우선 서명을 제거하면 GHC가 그에 대해 불평합니다 No instance for (Foldable t0) arising from a use of ‘foldr’. 함수의 유형이 모호하여 바인딩이 유추되었다고 말합니다 f :: t0 Char -> [Char]. 그리고 두 번째로 showHex에서 빈 문자열 인수를 제거 할 수 없으므로 빈 문자열 String -> String이 필요한 유형 별칭 인 ShowS를 반환 합니다.
sham1

@ sham1, 그렇습니다 ShowS. 문자열을 가져옵니다 ...하지만 하나 더합니다 (++). 그래서 당신은 동시에 둘 다 풀 수 있습니다. 그것이 실제로 그렇게 ShowS보이는 이유 입니다. 유형 오류가 발생하지 않으므로 버전이라고 생각합니까? 내가 지금 알았던 두 가지 다른 것 : otherwise항상 1<2(으로 단축 True) if할 수 있지만 대신 돌아 오면 e모든 이름을 인라인 하고 삭제할 수 있습니다. 그리고 접기를 concatMap, 즉 a로 바꿉니다 (>>=). 많이 절약하지는 않지만 적어도 조금은 절약합니다. 형식 오류도 해결할 수 있습니다.
MarLinn

0

파이썬 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 = 소스 문자열의 길이.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.