-
-
Save sebastien-p/1170594 to your computer and use it in GitHub Desktop.
function ( | |
a, // base62 encoded string | |
b, // placeholder for result | |
c, // placeholder for iterator | |
d // placeholder for char code | |
) { | |
for ( | |
b = c = ( // 'false - 1' will return '-1' and 'true - 1' will return '0' | |
a === (/\W|_|^$/.test(a += "") || a) // tests if 'a' is a properly base62-encoded string and coerces it to one | |
) - 1; // so, 'b' and 'c' are initialized with either '-1' or '0' | |
d = a.charCodeAt(c++); // if 'c' equals '-1', 'd' is 'NaN' which breaks the loop execution | |
) | |
b = b * 62 + d - [, 48, 29, 87][d >> 5]; // See comments : https://gist.github.com/1170594#gistcomment-48129 | |
return b // positive base10 integer or '-1' if 'a' is not a base62 encoded string | |
} |
function(a,b,c,d){for(b=c=(a===(/\W|_|^$/.test(a+="")||a))-1;d=a.charCodeAt(c++);)b=b*62+d-[,48,29,87][d>>5];return b} |
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
Version 2, December 2004 | |
Copyright (C) 2011 Sebastien P. https://twitter.com/#!/_sebastienp | |
Everyone is permitted to copy and distribute verbatim or modified | |
copies of this license document, and changing it is allowed as long | |
as the name is changed. | |
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
0. You just DO WHAT THE FUCK YOU WANT TO. |
{ | |
"name": "base62 decode", | |
"description": "A JavaScript implementation of base62 decode.", | |
"keywords": [ | |
"base62", | |
"decode", | |
"string", | |
"number", | |
"integer" | |
] | |
} |
<!DOCTYPE html> | |
<title>Foo</title> | |
<div>Expected value: <b>3748986303764</b></div> | |
<div>Actual value: <b id="ret"></b></div> | |
<script> | |
var base62decode = function(a,b,c,d){for(b=c=(a===(/\W|_|^$/.test(a+="")||a))-1;d=a.charCodeAt(c++);)b=b*62+d-[,48,29,87][d>>5];return b}; | |
document.getElementById("ret").innerHTML = base62decode("140bytes") | |
</script> |
@atk : thanks, the b=b*62+d-[,48,29,87][d>>5]
part is awesome, exactly what I needed !
You're welcome, @sebastien-p :-)
I would really like to see more comments in the annotated part. I have only just worked out what the first part of the for loop does (leading to the false-y charCodeAt(-1) in the second for-loop-part if a is not string or not base62).
@atk : is it better now ? :) Can you explain the line I kept from your code as I don't always understand well those bitwise tricks ? Thanks.
Thanks, much better now. Of course I can explain this line (except of the b*62 part, which seems pretty self-explaining to me):
// We are expecting either numbers (ascii 48-58), uppercase letter (ascii 65-90) and lowercase letters (ascii 97-122)
// and want to map the numbers to 0-9, the uppercase letters to 36-61 and the lowercase letters to 10-35; therefore,
// we integer divide the character code by 32 using shift right 5, so numbers will yield 1, uppercase letters 2 and lowercase 3
// and let this result select the corresponding substractor from a sparse array (because the extra comma is smaller than -1):
[,48,29,87][d>>5]
@atk : thank you, I understand it a little more now :) but still don't manage to apply this kind of hack to the encoding function :(
it does not apply there, because we'd need another formula than d>>5 to filter 0-9, 10-35 and 36-61 to 0, 1 and 2. If I find one, I'll tell you.
@atk : I would be very interested to know, thank you.
no formula I could think of would be shorter than x>35?87:x>10?29:48
.
@atk : ok, thanks. If you want to help, I released the new version of the encoding function, still 4 bytes to go :) https://gist.github.com/1168420
a === (/\W|_/.test(a += "") || a)
could be great instead of a === (a += "") && /^[a-z\d]+$/i.test(a)
but sadly doesn't prevent passing an empty string as argument.
how about saving at least 1 byte with a===(/^[a-z\d]+$/i.exec(a)||0)[0]
which should take care of empty strings? Or even shorter: a===(/\W|_|^$/.test(a)||a)
in which we use the property of /^$/ to match empty strings?
@atk : thanks, base62 decode is now 4 bytes shorter :)
@sebastien-p: test coerces its argument to string, so a+=''
has no function there. You may want to use a===(/\W|_|^$/.test(a)||a+'')
@atk : yep, I know, but a
needs to be a string for a.charCodeAt(c++)
to work, so I force coercion here on purpose.
For a not to be a string and to be coerced to a string that coerced into a valid base62 string, it would have to be an object with a toString method, so handling non-strings is rather pointless, isn't it?
@atk : you're right, input value validation is optional and the whole entry would be shorter without it. I added it because it fits and mostly because I needed the function to be designed this way.
true // -1
false // -1
I found this useful and converted it into C# if anyone ever needs it. Not intended to be 140 bytes small.
A less safe, but very small base62 decoder: