12
\$\begingroup\$

URLs are getting too long. So, you must implement an algorithm to shorten a URL.

i. The Structure of a URL

A URL has 2 main parts: a domain and a path. A domain is the part of the URL before the first slash. You may assume that the URL does not include a protocol. The path is everything else.

ii. The Domain

The domain of a URL will be something like: xkcd.com meta.codegolf.stackexcchhannnge.cooom. Each part is period-seperated, e.g. in blag.xkcd.com, the parts are "blag", "xkcd", and "com". This is what you will do with it:

  • If it contains more than two parts, put the last two aside and concatenate the first letter of the rest of the parts.

  • Then, concatenate that to the first letter to the second-to-last part.

  • Add a period and the second and third letter of the second-to-last part.

  • Discard the last part.

iii. The Path

The path will be like: /questions/2140/ /1407/. As before, "parts" are seperated by slashes. For each part in the path, do:

  • Add a slash

  • If it is completely made of base-ten digits, interpret it as a number and convert to a base-36 integer.

  • Otherwise, add the first letter of the part.

At the end, add a slash.

iv. Misc.

  • This is , so shortest code wins.
  • The path can be empty, but the URL will always end with a slash.
  • There will not be a protocol (e.g. http://, file:///)
  • There will never be less than two parts in the domain.
  • Standard loopholes apply.

Examples

In: xkcd.com/72/
Out: x.kc/20/

In: math.stackexchange.com/a/2231/
Out: ms.ta/a/1pz/

In: hello.org/somecoolcodeintrepreteriijjkk?code=3g3fzsdg32,g2/
Out: h.el/s/

\$\endgroup\$
2
  • \$\begingroup\$ In your last example, doesn't the path end at kk and everything starting with ? is a query string, which shouldn't end with a slash? Also not all URLs will end with a slash /, like www.something.com/path. Or is this irrelevant for the purpose of this challenge? \$\endgroup\$ Jan 22, 2016 at 8:57
  • \$\begingroup\$ That is irrelevant. \$\endgroup\$
    – user46167
    Jan 24, 2016 at 20:07

5 Answers 5

4
\$\begingroup\$

JavaScript (ES6), 149 bytes

u=>u.split`/`.map((p,i)=>i?/^\d+$/.test(p)?(+p).toString(36):p[0]:(d=p.split`.`).slice(0,-1).map((s,j)=>s[l=j,0]).join``+"."+d[l].slice(1,3)).join`/`

Explanation

I made this independent of @Neil's solution but it ended up looking very similar.

u=>
  u.split`/`.map((p,i)=>       // for each part p at index i
    i?                         // if this is not the first part
      /^\d+$/.test(p)?         // if p is only digits
        (+p).toString(36)      // return p as a base-36 number
      :p[0]                    // else return the first letter
    :
      (d=p.split`.`)           // d = domain parts
      .slice(0,-1).map((s,j)=> // for each domain part before the last
        s[l=j,0]               // return the first letter, l = index of last domain part
      ).join``
      +"."+d[l].slice(1,3)     // add the 2 letters as the final domain
  )
  .join`/`                     // output each new part separated by a slash

Test

var solution = u=>u.split`/`.map((p,i)=>i?/^\d+$/.test(p)?(+p).toString(36):p[0]:(d=p.split`.`).slice(0,-1).map((s,j)=>s[l=j,0]).join``+"."+d[l].slice(1,3)).join`/`
<input type="text" id="input" value="math.stackexchange.com/a/2231/" />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

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

Pyth, 93 85 bytes

Lsm@+jkUTGdjb36J<zxz\/KP>zhxz\/=cJ\.pss[mhd<J_2hePJ\.<tePJ2\/;=cK\/sm+?-djkUThdysd\/K

Hand-compiled to pythonic pseudocode:

                z = input()                     # raw, unevaluated
                G = "abcdefghijklmnopqrstuvwxyz"
                k = ""
                T = 10
L               def y(b):                       # define y as base10to36
 sm                 join(map(lambda d:
  @+jkUTGd            (join(range(T),interleave=k)+G)[d],
                                                # the join(..)+G makes "0...9a...z"
  jb36                 convert(b,36)            # returns a list of digit values in base10
J<zxz\/         J = z[:z.index("\/")]           # domain portion
KP>zhxz\/       K = z[1+z.index("\/"):][:-1]    # path portion
=cJ\.           J = J.split(".")                # splits domain into parts
pss[            no_newline_print(join(join[     # 1 join yields a list, the other a string
 mhd<J_2            map(lambda d:d[0],J[:-2]),
 hePJ               J[:-1][-1][1],
 \.                 ".",
 <tePJ2             J[:-1][-1][1:][:2],
 \/                 "\/"
;               ])
=cK\/           K = K.split("\/")
sm              print(join(map(lambda d:
 +?-djkUThdysd\/    "\/"+(d[0] if filterOut(d,join(range(T),interleave=k)) else y(int(d))),
                    # the filter will turn pure number into empty string, which is False
 K                  K)))

Finally, the excruciation ends...

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

JavaScript ES6, 157 bytes

u=>u.split`/`.map((p,i)=>i?/^\d+$/.test(p)?(+p).toString(36):p[0]:p.split`.`.reverse().map((h,i)=>i--?i?h[0]:h[0]+'.'+h[1]+h[2]:'').reverse().join``).join`/`

Edit: Saved 4 bytes thanks to Doᴡɴɢᴏᴀᴛ.

\$\endgroup\$
2
  • \$\begingroup\$ You should be able to make .split('/') and .split('.') into string templates \$\endgroup\$
    – Downgoat
    Jan 21, 2016 at 21:32
  • \$\begingroup\$ @Doᴡɴɢᴏᴀᴛ Bah, I remembered on join as well! \$\endgroup\$
    – Neil
    Jan 21, 2016 at 21:39
1
\$\begingroup\$

Python 2, 378 365 Bytes

Update

Golfed it down by a bit. The ~150 Bytes for the base36-function are annoying, but I can't get rid of it until python has a builtin for that...

def b(n):
 a=abs(n);r=[];
 while a :
    r.append('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'[a%36]);a//=36
 if n<0:r.append('-')
 return''.join(reversed(r or'0'))
u=raw_input();P=u.split("/")[0].split(".")
print"".join([p[0] for p in P[0:-2]]+[P[-2][0]]+["."]+list(P[-2])[1:3]+["/"]+[b(int(p))+"/"if p.isdigit()else p[0]+"/" for p in u.split(".")[-1].split("/")[1:-1]])

Old version

def b(n):
 a=abs(n)
 r=[]
 while a:
    r.append('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'[a%36])
    a//=36
 if n<0:r.append('-')
 return''.join(reversed(r or'0'))
u=raw_input()
P=u.split("/")[0].split(".")
s=""
if len(P)>2:
 for p in P[:-2]:s+=p[0]
s+=P[-2][0]+"."+P[0][1:3]
P=u.split(".")[-1].split("/")[1:-1]
for p in P:
 s+="/"+(b(int(p)) if p.isdigit() else p[0])
print s+"/"

Since Python does not have a builtin way to convert ints to a base36-String, I took the implementation from numpy and golfed it down. Rest is pretty straightforward, I will golf it down more after work. Suggestions always appreciated in the meantime!

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

Pyhton 2, 336 329 bytes

update

fixed and shorter thanks to webwarrior

def b(a):
 r=''
 while a:
  r+=chr((range(48,58)+range(65,91))[a%36])
  a//=36
 return ''.join(reversed(r or '0'))
u=raw_input()
P=u.split('/')[0].split('.')
s=''
if len(P)>2:
 for p in P[:-2]: s+=p[0]
s+=P[-2][0]+'.'+P[0][1:3]
P=u.split('.')[-1].split('/')[1:]
for p in P: s+='/'+(b(int(p)) if p.isdigit() else p[0])
print s+'/'

original

DenkerAffe's version with some mods : correctly handle "foo/bar?baz" scheme, plus, no need for negative case in the base36 conversion function.

 def b(a):
 r=''
 while a:
  r+=('0123456789ABCDEFGHUKLMNOPQRSTUVWXYZ'[a%36])
  a//=36
 return ''.join(reversed(r or '0'))
u=raw_input()
P=u.split('/')[0].split('.')
s=''
if len(P)>2:
 for p in P[:-2]: s+=p[0]
s+=P[-2][0]+'.'+P[0][1:3]
P=u.split('.')[-1].split('/')[1:]
for p in P: s+='/'+(b(int(p)) if p.isdigit() else p[0])
print s+'/'
\$\endgroup\$
1
  • \$\begingroup\$ There's error in your lookup string, and also the whole line can be shorter: r+=chr((range(48,58)+range(65,91))[a%36]) \$\endgroup\$
    – webwarrior
    Jan 23, 2016 at 22:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.