isync has asked for the wisdom of the Perl Monks concerning the following question:

Possibly, for our cookbook section:
I started porting alphaID to perl (would someone help me finish it?):

Related reading: related blog post, github ()
Related modules: Math::Base36, MIME::Base64, number.toString() (JS)

(Might be easier to wrap Data::ID::Exim but I couldn't figure out if it *really* does the same, and what ndigits does. Which is sad, as the code looks more efficient..)

#!/usr/bin/perl use MIME::Base64; use Math::Base36 ':all'; my $value = 64000; print "$value MIME::Base64-> "; my $encoded = encode_base64($value); chomp($encoded); print $encoded; my $decoded = decode_base64($encoded); print " back-> $decoded\n"; print "$value Math::Base36-> "; $encoded = encode_base36($value); print $encoded; $decoded = decode_base36($encoded); print " back-> $decoded\n"; print "$value Math::Base62-> "; $encoded = Math::Base62::encode_base62($value); print $encoded; $decoded = Math::Base62::decode_base62($encoded); print " back-> $decoded\n"; package Math::Base62; use warnings; use strict; sub encode_base62 { return alphaID(shift); } sub decode_base62 { return alphaID(shift,1); } ## port of: https://raw.github.com/kvz/kvzlib/master/php/functions/alp +haID.inc.php sub alphaID { my ($in, $to_num, $pad_up, $passKey) = @_; my $index = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQ +RSTUVWXYZ"; # if($passKey) { # Although this function's purpose is to just make the # ID short - and not so much secure, # with this patch by Simon Franz (http://blog.snaky.org/) # you can optionally supply a password to make it harder # to calculate the corresponding numeric ID # for(my $n = 0; $n<length($index); $n++) { # $i[$n] = substr($index,$n,1); # } # $passhash = hash('sha256',$passKey); # $passhash = (strlen($passhash) < strlen($index)) # ? hash('sha512',$passKey) # : $passhash; # for ($n=0; $n < strlen($index); $n++) { # $p[] = substr($passhash, $n ,1); # } # array_multisort($p, SORT_DESC, $i); # $index = implode($i); # } my $base = length($index); my $out; if($to_num) { # Digital number <<-- alphabet letter code $in = reverse($in); $out = 0; my $len = length($in) - 1; for(my $t = 0; $t <= $len; $t++) { my $bcpow = $base**($len - $t); $out = $out + index($index, substr($in, $t, 1)) * $bcpow +; } # if($pad_up =~ /\d+/) { # $pad_up--; # if ($pad_up > 0) { # $out -= pow($base, $pad_up); # } # } $out = sprintf('%F', $out); $out = substr($out, 0, index($out, '.')); } else { # Digital number -->> alphabet letter code # if (is_numeric($pad_up)) { # $pad_up--; # if ($pad_up > 0) { # $in += pow($base, $pad_up); # } # } $out = ''; for(my $t = int( log($in)/log($base) ); $t >= 0; $t--) { my $bcp = $base**$t; my $a = int($in / $bcp) % $base; $out = $out . substr($index, $a, 1); $in = $in - ($a * $bcp); } $out = reverse($out); } return $out; }

Replies are listed 'Best First'.
Re: RFC: Math::Base62
by BrowserUk (Patriarch) on Oct 04, 2011 at 16:19 UTC

    These are considerably more concise :

    use constant BASE62 => join '', 'a'..'z', 0 .. 9, 'A'..'Z'; sub toBase62 { use integer; my $n = shift; my @out; push( @out, substr( BASE62, $n % 62, 1 ) ), $n /= 62 while $n; join '', @out; } sub fromBase62 { my $t = reverse shift; my $n = 0; $n *= 62, $n += index( BASE62, substr( $t, 0, 1, '') ) while lengt +h $t; return $n }

    and quite a bit more efficient:

    #! perl -slw use 5.010; use strict; use Benchmark qw[ cmpthese ]; use Math::Random::MT qw[ rand ]; ... our @data = map int( rand 2**32 ), 1 .. 1000; cmpthese -1, { yourn => q[ $_ == alphaID( alphaID( $_, 0 ), 1 ) or die "Yourn $_" for @data; ], mine => q[ $_ == fromBase62( toBase62( $_ ) ) or die "mine $_" for @data; ], }; __END__ C:\test>junk25 Rate yourn mine yourn 49.2/s -- -48% mine 93.9/s 91% --

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks for your effort and for sharing expert-quality code!

      (Anyone willing to package it for us for cpan, just append to this thread.)