-3
\$\begingroup\$

Challenge

I think everyone of us heard of URL encoding mechanism - it's basically everywhere.

Given an URLEncoded string on stdin, decode it, and output the decoded form to stdout.

The encoding is very simple, + or %20 is representing space. Every percent followed by two hex digits (uppercase or lowercase) has to be replaced with ASCII character code of this number.

Related, but it's the other way round

Example

100%25+working
=>
100% working

%24+%26+%3C+%3E+%3F+%3B+%23+%3A+%3D+%2C+%22+%27+%7E+%2B+%25
=>
$ & < > ? ; # : = , " ' ~ + %

%414243
=>
A4243

Test case that fails:

%24%XY+%%%
   ^~~~~~~
=>
$

Rules

  • Loopholes are forbidden.
  • If your programming language has built-in function to decode the URL, using it (the function) is forbidden.
  • Assume ASCII character set. No Unicode and all that stuff.
  • This is a code-golf, so the answer with the fewest bytes used to accomplish the task wins.
  • Please include a link to an online interpreter for your code.
  • Your program has to decode until EOF or an error (eg. percent without valid hex digits - %xy) is spotted (you can safetly terminate).
  • If anything is unclear, please let me know down in the comments.
\$\endgroup\$
  • 5
    \$\begingroup\$ * has to decode until * ... this feels like it assumes a specific method of solving the problem, i.e that you will decode left to right. \$\endgroup\$ – Expired Data Aug 2 at 9:58
  • 4
    \$\begingroup\$ The whole validation part of this is just additional to the challenge. I don't see why it's added on, it makes it two separate challenges. i.e URL decode a string (the named challenge) and validate whether a string is a valid URL encoded string (which is a different challenge imo) \$\endgroup\$ – Expired Data Aug 2 at 10:05
  • 2
    \$\begingroup\$ Who says I'm going to read it right to left, what if I split the input by %, and then do my work. What if I read right to left and determine if I see two characters and then a percent and then do work on it etc. etc. just because you aren't capable of understanding how a problem may be solved doesn't make it the impossible. \$\endgroup\$ – Expired Data Aug 2 at 10:09
  • 5
    \$\begingroup\$ (also, you could change the name of the challenge to "Decode the URL as far as possible" or similar - I don't think it's a bad challenge at all if you set the correct expectations from the start) \$\endgroup\$ – Sanchises Aug 2 at 10:50
  • 6
    \$\begingroup\$ Does it absolutely need to be stdin, rather than default IO rules? Also, agreed the required input validation makes it feel like a chameleon challenge... on some platforms the code to do that may be longer than the actual challenge. \$\endgroup\$ – 640KB Aug 2 at 20:26

10 Answers 10

4
\$\begingroup\$

05AB1E, 41 30 bytes

'+ð:Δć©'%Qi2ôćuDHç©Ç`hÊiq}J}®?

-11 bytes thanks to @Grimy.

Try it online or verify all test cases.

Explanation:

'+ð:                  '# Replace all "+" in the (implicit) input with spaces
Δ                      # Loop until the result no longer changes:
 ć                     #  Extract head; pop and push remainder-string and first character
  ©                    #  Store the character in variable `®` (without popping)
   '%Qi               '#  If this character is a "%":
       2ô              #   Split the remainder-string into parts of size 2
                       #    i.e. "abcde" → ["ab","cd","e"]
         ć             #   Extract head again
          u            #   Convert it to uppercase
           D           #   Duplicate it
            H          #   Convert it from hexadecimal to integer
                       #   (NOTE: even if it isn't a valid hexadecimal string,
                       #    it will still result in an integer regardless)
             ç         #   And then from integer to ASCII-character with this codepoint
              ©        #   Replace variable `®` with this (without popping)
               Ç`h     #   Reverse process: ASCII-character → integer → hexadecimal string
                  Êi   #   If both are NOT equal (so it initially was invalid hexadecimal):
                    q  #    Stop the program
                   }J  #   And join the list of 2-char strings back together
      }®?              #  And then print `®` without newline
\$\endgroup\$
  • 1
    \$\begingroup\$ Fails on lowercase (challenge explicitly says lowercase hex has to be handled too). \$\endgroup\$ – Grimy Aug 2 at 13:02
  • 1
    \$\begingroup\$ @Grimy Straight-forward fix with +3 bytes for now (adding Dl«). Thanks for reporting. I did check if H would convert lowercase or mixed case characters correctly, but forgot about my å check.. \$\endgroup\$ – Kevin Cruijssen Aug 2 at 13:09
  • \$\begingroup\$ 36 \$\endgroup\$ – Grimy Aug 2 at 13:41
  • 1
    \$\begingroup\$ 30 \$\endgroup\$ – Grimy Aug 2 at 13:47
  • \$\begingroup\$ @Grimy Nice, thanks. :) \$\endgroup\$ – Kevin Cruijssen Aug 2 at 15:39
3
\$\begingroup\$

Gema, 45 characters

+= 
%<X2>=@int-char{@radix{16;10;$1}}
%=@fail

Insensitive on hexadecimal case.

Sample run:

bash-5.0$ gema '+= ;%<X2>=@int-char{@radix{16;10;$1}};%=@fail' <<< $'100%25+working\n%24+%26+%3C+%3E+%3F+%3B+%23+%3A+%3D+%2C+%22+%27+%7E+%2B+%25\n%414243\n%24+%XY+%%%'
100% working
$ & < > ? ; # : = , " ' ~ + %
A4243
$ 

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Perl 5 (-0777p -Mre=/si), 45 bytes

s/%.?[^\da-f].*//;y/+/ /;s/%(..)/chr hex$1/ge

TIO

\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 92 bytes

f=([x,y,z,...a])=>x=='%'?1/(n='0x'+y+z)?Buffer([n])+f(a):'':x?(x=='+'?' ':x)+f([y,z,...a]):a

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 3, 90 bytes

def d(s):t='%'!=s[0];print(end=t*s[0].replace('+',' ')or chr(int(s[1:3],16)));d(s[3-2*t:])

Try it online!

Explanation

Checks if the first character is %. If that is the case, it will try to hex-decode the following two characters and print the result. If not, it will just print the first character and replaces x with if necessary.

If the first character was %, the first three characters are sliced off the string and the function is called recursively. If not, only the first character is sliced off and the function is called again.

Raises an error if the hex string cannot be decoded or if end of line is reached.

\$\endgroup\$
1
\$\begingroup\$

Jelly, 35 bytes

ṣ”+Kṣ”%µḊḢ;ḢƊ€ŒuØHiⱮⱮ’ḅ⁴⁸żFO<0œṗƊḢỌ

Try it online!

A monadic link that takes a string as its argument and returns the decoded string, terminating early at any invalid hex.

I’ve assumed for now that standard I/O rules apply. If it really has to be stdin, that will cost a byte.

\$\endgroup\$
0
\$\begingroup\$

Perl 6, 62 bytes

{S:g{(<-[%]>*)\%?(..)?}={TR/+/ /}($0).print+print chr "0x"~$1}

Try it online!

Anonymous code block that outputs to STDOUT and then errors. This assumes that the input cannot contain spaces.

\$\endgroup\$
0
\$\begingroup\$

Charcoal, 65 bytes

≔E¹⁶⍘ιφθWθ«≔⮌⪪S%ι⊟ιW∧ι⊟ι«¿∧›Lκ¹⬤01№θ↧§κμ«℅⍘↧…겦¹⁶✂κ²»«≔υι≔υθ»»D⎚

Try it online! Link is to verbose version of code. Note that Charcoal prompts "Enter input:" if it runs out of input. Explanation:

≔E¹⁶⍘ιφθ

Grab the list of hex digits into a variable.

Wθ«

Repeat while the variable is not empty. This is used as a flag to break out of the loop, since Charcoal has no other way of terminating the loop.

≔⮌⪪S%ι

Read the next line of text and split it on %s.

⊟ι

Output the first split.

W∧ι⊟ι«

Repeat while there are more splits to process, but stop if any of them are empty.

¿∧›Lκ¹⬤01№θ↧§κμ«

Also check that the length of the split is at least 2 and that the first 2 characters are hex digits. (Inconveniently I can't use a literal 2, I have to use a string of length 2 instead.)

℅⍘↧…겦¹⁶

Convert the first two characters from hex and output the character with that code.

✂κ²

Output the rest of that split.

»«≔υι≔υθ»»D⎚

Otherwise clear the loop variables so that we terminate processing. The canvas is also printed after each loop as otherwise Charcoal's input handling gets in the way again.

\$\endgroup\$
0
\$\begingroup\$

Python 3, 91 bytes

lambda s:re.sub('%([A-Fa-f\d]{2})',lambda t:chr(int(t[1],16)),s.replace('+',' '))
import re

Try it online!

Approach this with regular expressions.

\$\endgroup\$
  • \$\begingroup\$ Nice approach, but prints $%XY %%% instead of $ in the fourth example. \$\endgroup\$ – Jitse Aug 3 at 7:49
0
\$\begingroup\$

Stax, 29 bytes

í☼∩ò☺µ◘Γπ╓l▄╓█₧ß:♦+ÇP¢Y╚↑░ºHÑ

Run and debug it

It's mostly regex.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.