7
\$\begingroup\$

The challenge is this:

You are given a url that is as follows:

http://sub.example.com/some/dir/file.php?action=delete&file=test.foo&strict=true

There can be either http or https, there can be any number of subdomains or directories, and the end file can have any name.

You are to create a full program (that can be compiled/interpreted) that when given a key will return the correct value and if no key is found it will return an empty string.

For example:

> https://example.com/index.php?action=delete
...> get(action) #=> delete
> https://this.example.com/cat/index.php?action=delete
...> get(action) #=> delete
> http://example.com, https://action.example.com/actionscript/action.jpg
...> get(action) #=> none
> https://example.com/index.php?genre=action&reaction=1&action=2
...> get(action) #=> 2

There are no language restrictions and score is calculated a 1 point for every byte. Smallest score wins.

To clarify:

  • You do not need to handle URL encoding
  • The script only needs to run once and produce a result
  • The script can take any input form: STDIN, Prompt, even passed as a function argument

Example:

Javascript, 101 105 bytes

function p(k){var m;return((m=location.href.match(new RegExp('.*[&\?]'+k+'=([^&]*).*')))!==null?m[1]:'');}
\$\endgroup\$
  • \$\begingroup\$ What about URL encoding? If I recall correctly there are at least two different RFCs on that, which are not compatible. Should we support URL encoding at all, and if so, in which form? \$\endgroup\$ – Martin Ender Jun 4 '15 at 22:37
  • \$\begingroup\$ You do not need to support URL encoding, the only thing you have to do is get the value of the key encoded or not. \$\endgroup\$ – Benjamin Williams Jun 4 '15 at 22:38
  • 1
    \$\begingroup\$ I think this question needs more test cases. Could you please add the expected results for each of the following URLs (all with query key action): http://example.com, https://action.example.com/actionscript/action.jpg, https://example.com/index.php?genre=action&reaction=1&action=2 \$\endgroup\$ – Sp3000 Jun 5 '15 at 1:59
  • 1
    \$\begingroup\$ You can assume that the url will look exactly like the four examples above. \$\endgroup\$ – Benjamin Williams Jun 5 '15 at 2:26
  • 2
    \$\begingroup\$ It appears you unaccepted the shortest answer and accepted a longer one. Since this is a code golf competition, the answer with the smallest byte count should win, which in this case is Maltysen's Pyth answer. \$\endgroup\$ – Alex A. Jul 20 '15 at 4:13

16 Answers 16

6
\$\begingroup\$

Pyth - 22 21 18 bytes

Uses the obvious method of constructing a dictionary and using } to check existence. Thanks to @FryAmTheEggman for the error handling trick.

#@.dcR\=cecw\?\&zq

Can probably be golfed a little more. Doing explanation now. Added explanation:

#                 Error handling loop
 @                Implicitly print dict lookup
  .d              Dictionary constructor, takes list of pairs
   cR\=           Map split with "=" as the second arg
    c    \&       Split by "&"
     e            Last in sequence of
      c           Split
       w          Second input
       \?         By "?"
 q                Quit loop

Try it online here.

\$\endgroup\$
  • 1
    \$\begingroup\$ #@.dcR\=cecw\?\&zq seems to work. Not 100% this works all the time, but basically it uses try/catch to check for the dictionary containing the element. \$\endgroup\$ – FryAmTheEggman Jun 5 '15 at 4:05
  • \$\begingroup\$ @FryAmTheEggman oh that's really smart. Thanks. \$\endgroup\$ – Maltysen Jun 5 '15 at 14:41
9
\$\begingroup\$

Retina, 30 27 bytes

!`(?<=^\1 .*[?&](.*)=)[^&]+

This is a full program that expects the key and the URL to be space-separated on STDIN, e.g.

action http://sub.example.com/some/dir/file.php?action=delete&file=test.foo&strict=true

This is essentially just a (.NET-flavoured) regex, which matches the correct value by checking that the preceding key is equal to the first string in the input (using a backreference). The only thing that's a bit odd about the regex is that .NET matches lookbehinds from right to left, which is why the "backreference" actually references a group that appears later in the pattern. The !` instructs Retina to print the actual match (if there is one) instead of the number of matches.

For those who don't regex, here is an annotated version. Read the lookbehind from the bottom up, because that's how it's processed:

(?<=        # A lookbehind. Everything we match in here will not be returned as part of
            # actual match. Start reading this from the corresponding parenthesis.
  ^         # Ensure we're at the beginning of the input, so that we've checked
            # against the entire input key.
  \1        # Backreference to the key to check that it's the one we've asked for.
  [ ]       # Match a space.
  .*        # Consume the rest of the URL.
  [?&]      # Match a ? or a & to ensure we've actually captured the entire key.
  (         # End of group 1.
    .+      # Match the key.
  )         # Capturing group 1. Use this to keep track of the key.
  =         # Make sure we start right after a '='
)           # Start reading the lookbehind here.
[^&]+       # Match the value, i.e. as many non-& characters as possible.
\$\endgroup\$
  • \$\begingroup\$ Very intuitive. \$\endgroup\$ – Benjamin Williams Jun 4 '15 at 22:49
  • \$\begingroup\$ @BenjaminWilliams Added more detail to the explanation. (And fixed a small bug.) \$\endgroup\$ – Martin Ender Jun 4 '15 at 22:58
  • 4
    \$\begingroup\$ @BenjaminWilliams This is not the shortest answer and shouldn't be the accepted one. (As this is code-golf.) \$\endgroup\$ – Calvin's Hobbies Jul 20 '15 at 4:11
6
\$\begingroup\$

Perl, 25 bytes

/[?&]$^I=([^&]*)/;$_=$1

This reads the URL from STDIN and the key as an argument to -i. It also requires the -p switch. I've added two bytes to the count to account for i and p.

Example

$ perl 2>&- -e'/[?&]$^I=([^&]*)/;$_=$1' -piaction <<< 'http://example.com/?action=delete'
delete
\$\endgroup\$
  • \$\begingroup\$ I don't think you need to add 1 byte for the -i flag, since it is used to pass the 2nd part of the input. \$\endgroup\$ – Ismael Miguel Jun 5 '15 at 15:11
  • \$\begingroup\$ -i is normally used to provide a backup extension, so it isn't a standard input method. Counting it seemed fair, and I'm not winning any prizes anyway. \$\endgroup\$ – Dennis Jun 5 '15 at 17:34
6
\$\begingroup\$

JavaScript (ES6) 64

Edit Saved 1 byte thx @ismael-miguel

A function with url and key as parameters.

Test running the snippet in Firefox.

f=(u,k,e='')=>u.replace(RegExp(`[?&]${k}=([^&]*)`),(m,g)=>e=g)&&e

// TEST
out=x=>O.innerHTML += x+'\n';

test=[
   'https://example.com/index.php?action=delete',
   'https://this.example.com/cat/index.php?action=delete',
   'http://example.com', 
   'https://action.example.com/actionscript/action.jpg',
   'https://example.com/index.php?genre=action&reaction=1&action=2'
]

test.forEach(u=>out('Url '+u+'\nValue ['+f(u,'action')+']'))
<pre id=O></pre>

\$\endgroup\$
  • 1
    \$\begingroup\$ Save 1 byte by replacing your regex with `[?&]${k}=([^&]*)` \$\endgroup\$ – Ismael Miguel Jun 6 '15 at 15:08
4
\$\begingroup\$

Bash - 55 53

2 bytes saved thanks to izabera

[[ $1 =~ [?\&]$2=([^&]*) ]]
echo ${BASH_REMATCH[1]}

Takes the URL as the first arg and the key to find as the second.

bash url.sh "https://this.example.com/cat/index.php?action=delete&foo=bar&spam=eggs" spam  
\$\endgroup\$
  • \$\begingroup\$ [?\&]$2=([^&]*) \$\endgroup\$ – izabera Jun 5 '15 at 6:10
4
\$\begingroup\$

Python, 87 bytes

The script takes the first url as the first argument and the key as the second.

 import re,sys;print re.search(r'[?|&]'+sys.argv[2]+'+=([a-z.]+)',sys.argv[1]).group(1);

Sample output:

>> runfile('test.py', args='http://sub.example.com/some/dir/file.php?action=delete&file=test.foo&strict=true file')
>> test.foo 
\$\endgroup\$
4
\$\begingroup\$

PHP 4.1, 4336 bytes

There's no mention to do not use built-in function, so, here is my go:

<?=parse_str(parse_url($U,6))?0:$$P;

This restricts the use of the keys U and P on your URL.
You can pass the data as you please (POST, GET, COOKIE, ...), being the key U the url and P the parameter.

Thank you, @manatwork for this shorter version!

Also, an alternative, without the previous restrictions:

<?=parse_str(parse_url($U,6),$A)?0:$A[$P];

Old versions:

<?parse_str(parse_url($U,6),$A);echo$A[$P];

If you are fine with not being able to use the keys U and P:

<?parse_str(parse_url($U,6));echo$$P;
\$\endgroup\$
  • 1
    \$\begingroup\$ That's generally considered a standard loophole \$\endgroup\$ – Toby Speight Jun 5 '15 at 12:37
  • \$\begingroup\$ @TobySpeight There's generally saying that standard loopholes are disallowed, which isn't the case. \$\endgroup\$ – Ismael Miguel Jun 5 '15 at 12:48
  • 1
    \$\begingroup\$ @TobySpeight: That link doesn't go where you think it does. (You missed the meta..) \$\endgroup\$ – Dennis Jun 5 '15 at 12:59
  • 2
    \$\begingroup\$ @Ismael - not disallowed, just not very interesting. Sorry. \$\endgroup\$ – Toby Speight Jun 5 '15 at 13:56
  • 1
    \$\begingroup\$ @manatwork That does't work on PHP4.1, but <?=parse_str(parse_url($U,6))?0:$$P; works as expected. That's because the syntax false?:default is only available from PHP5.3 and up. But I will include your examples. \$\endgroup\$ – Ismael Miguel Jun 5 '15 at 14:45
3
\$\begingroup\$

CJam, 22 bytes

l'?'&er"&="l*/1>s'&/0=

Try it online in the CJam interpreter.

How it works

l      e# Read a line from STDIN.
'?'&er e# Replace question marks with ampersands.
"&="l* e# Place the second line from STDIN between '&' and '='.
/      e# Split the first string at occurrences of the second.
1>s    e# Discard the first chunk.
'&/0=  e# Discard everything following an ampersand.
\$\endgroup\$
2
\$\begingroup\$

Pyth, 25 bytes

|smecd\=fqhcT\=zcecw\?\&"

Expects the input on two lines, the key followed by the URL.

Explanation

                   cw\?     Split the second input (the URL) by "?"
                  e         The end (the parameter list)
                 c     \&   Split the parameter list by "&"
        f                   Filter each parameter T
            cT\=            Split by "="
           h                The first part (the key)
          q     z           Equals the first input (the search key)
  m                         Map each valid parameter d
    cd\=                    Split d by "="
   e                        The value
 s                          Print as a string
|                        "  Otherwise, if the key isn't found, print nothing

Try it here

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

Bash, 37

a=${2#*\?};eval "${a//&/;};echo \$$1"

Pass the key in the first argument and the URL in the second.

Strips everything off up to and including the first ?, then treats the remainder as a series of assignments (RFC 1738 URLs can't contain spaces or any of the shell metacharacters, so this works). Finally, print the requested result; by default, strings not found are assumed empty.

Limitation - any key that already exists in the environment may be 'found' when not present in the input.

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

Rebol - 97

e:["&"| end]p: func[u a][parse u[thru"?"any[copy k to"=""="copy v to e e(if k = a[return v])]]{}]

Ungolfed:

e: ["&" | end]

p: func [u a] [
    parse u [
        thru "?"
        any [
            copy k to "=" "=" copy v to e e
            (if k = a [return v])
        ]
    ]
    {}
]

Example usage (in Rebol console):

>> p "http://sub.example.com/some/dir/file.php?action=delete&file=test.foo&strict=true" "action"
== "delete"

>> p "https://example.com/index.php?action=delete" "action"
== "delete"

>> p "https://this.example.com/cat/index.php?action=delete" "action"
== "delete"

>> p "http://example.com, https://action.example.com/actionscript/action.jpg" "action"
== ""

>> p "https://action.example.com/actionscript/action.jpg" "action"                     
== ""

>> p "http://example.com" "action"                                                     
== ""

>> p "https://example.com/index.php?genre=action&reaction=1&action=2" "action"
== "2"
\$\endgroup\$
1
\$\begingroup\$

Javascript, 235 228 203 190 bytes

Takes the URL as the first input and the key as the second.

b=document.createElement('a'),b.href=prompt(u={}),a=b.search;if(a!=""){t=a.substring(1).split("&");for(i=t.length;i--;){p=t[i].split("=");u[p[0]]=p[1]}}c=u[prompt()];alert(c==undefined?"":c)
\$\endgroup\$
  • \$\begingroup\$ Interesting! I would like to offer up my 156 byte solution if you are okay with that. \$\endgroup\$ – Benjamin Williams Jun 4 '15 at 22:37
  • \$\begingroup\$ Go ahead, I guess. \$\endgroup\$ – SuperJedi224 Jun 4 '15 at 22:40
  • \$\begingroup\$ function p(k){var i,q=[],r=location.href.split('?')[1].split('&');for(i=0;i<r.length;i++){q=q.concat(r[i].split('='));}return(i=q.indexOf(k))>-1?q[i+1]:'';} \$\endgroup\$ – Benjamin Williams Jun 4 '15 at 22:42
  • \$\begingroup\$ The question does seem to be asking that the url be taken from the input. \$\endgroup\$ – SuperJedi224 Jun 4 '15 at 22:45
  • \$\begingroup\$ I went an clarified that in the question. \$\endgroup\$ – Benjamin Williams Jun 4 '15 at 22:48
1
\$\begingroup\$

K, 24

{((!)."S=&"0:*|"?"\:x)y}

.

{((!)."S=&"0:*|"?"\:x)y}["https://example.com/index.php?genre=action&reaction=1&action=2";`genre]
"action"

Explanation:

The function takes two parameters, the url x and the key y

First we split the url on the ? character.

k)"?"\:"https://example.com/index.php?genre=action&reaction=1&action=2"
"https://example.com/index.php"
"genre=action&reaction=1&action=2"

Then we take the last element using *| (first reverse)

k)*|"?"\:"https://example.com/index.php?genre=action&reaction=1&action=2"
"genre=action&reaction=1&action=2"

Process the string using 0:. The LHS of 0: is a three character string, where the first is the datatype of the key (S for symbol, I for int etc), the second is the key-value delimiter (= in this case) and the third is the record delimiter (& here).

k)"S=&"0:*|"?"\:"https://example.com/index.php?genre=action&reaction=1&action=2"
genre    reaction action
"action" ,"1"     ,"2"

Turn this into a dictionary using !

k)(!)."S=&"0:*|"?"\:"https://example.com/index.php?genre=action&reaction=1&action=2"
genre   | "action"
reaction| ,"1"
action  | ,"2"

Then do a lookup on this dictionary for whichever key you're looking for.

k)((!)."S=&"0:*|"?"\:"https://example.com/index.php?genre=action&reaction=1&action=2")`genre
"action"

Turn it into a function using {} and replace the url string with x and the lookup key with y, then pass the url and key in as paramters (func[param1;param2;...;paramN])

k){((!)."S=&"0:*|"?"\:x)y}["https://example.com/index.php?genre=action&reaction=1&action=2";`genre]
"action"
\$\endgroup\$
  • \$\begingroup\$ Please include some text explaining your code. The post is recommended for deletion since you didn't. \$\endgroup\$ – mbomb007 Jul 9 '15 at 14:09
  • \$\begingroup\$ If you want an explanation you just have to ask. Explanations are not required, so please don't recommend a post of mine or anyone else's for deletion for this reason again \$\endgroup\$ – tmartin Jul 9 '15 at 15:38
  • \$\begingroup\$ Someone else recommended it. I was a reviewer. Also, code-only answers have always been discouraged. \$\endgroup\$ – mbomb007 Jul 9 '15 at 17:56
0
\$\begingroup\$

Gema: 44 38 characters

Expects first the parameter name then the URL on separate lines.

\B\L*\n=@set{p;$1}
\I$p\=/[^&]+/=$1
?=

Sample run:

bash-4.3$ gema -p '\B\L*\n=@set{p;$1};\I$p\=/[^&]+/=$1;?=' <<< $'action\nhttps://example.com/index.php?genre=action&reaction=1&action=2'
2
\$\endgroup\$
0
\$\begingroup\$

C, 123 bytes

char*f(char*s,char*n){for(char*x=n;*s&&(*x||*s!='=');x=*x++==*s++?x:n);return *s=='='?(n=strstr(s++,"&"))?(*n=0)?s:s:s:"";}

Note: this function assumes you aren't passing a constant char to it.

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

JavaScript, 40 bytes

u=>q=>new URL(u).searchParams.get(q)||``

Test it

\$\endgroup\$

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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