3

I would like to do something like the following in perl:

@digits = ("1", "2", ..., "a", ... "z", ... ); ## a list of characters
$num = 1033;
convert_to_base($num, @digits);

Now, $num will be converted to a string with the digits being used are from digits (so the base is $#digits + 1).

It can be done by iterating on $num, taking the modulo of $num with respect to $#digits and then dividing until 0 is reached, but I was wondering if there is any built-in function that does that in perl (or alternatively a fast function that would do it in perl).

phuclv
  • 37,963
  • 15
  • 156
  • 475
kloop
  • 4,537
  • 13
  • 42
  • 66
  • 6
    [Math::Base::Convert](http://p3rl.org/Math::Base::Convert) or maybe [Math::BaseCalc](http://p3rl.org/Math::BaseCalc) – choroba Mar 11 '15 at 09:37

2 Answers2

3

Using Math::Base::Convert as suggested in choroba's comment to the question:

#!/usr/bin/perl
use Math::Base::Convert "cnv";

my $num = 1033;

printf "%b", $num;           # binary:      10000001001
printf "%o", $num;           # octal:       2011
printf "%d", $num;           # decimal:     1033
printf "%x", $num;           # hexadecimal: 409
print cnv($num, 10, b64);    # base64*:     G9   (*: 0-9, A-Z, a-z, ., _)
print cnv($num, 10, b85);    # base85*:     CD   (*: from RFC 1924)
print cnv($num, 10, ascii);  # base96:      *s

Note, if you need to interpret this as a string, you may have to do e.g.
printf "%s", "" . cnv($num, 10, b85);

Adam Katz
  • 14,455
  • 5
  • 68
  • 83
  • Great answer! Btw, the `printf()` calls naturally do not depend on that CPAN module ( https://ideone.com/ke1CwR ), so if you're just doing hex, dec, bin, and oct bases, no CPAN-module installing is needed. – HoldOffHunger Mar 15 '20 at 14:01
  • 1
    I added an answer that includes how to do conversion from truly arbitrary bases. Make sure to check it out, since the CPAN pod isn't very clear on how to do this – insaner Feb 13 '21 at 00:53
2

As @Adam Katz mentioned in his answer, the way to do it is with Math::Base::Convert. However, your question is about using an arbitrary base. The CPAN pod isn't very clear on how to do it, but it's actually as easy as:

use strict;

use Math::Base::Convert;    # https://metacpan.org/pod/Math::Base::Convert

my $arb_enc = ['0'..'9', 'B'..'D', 'F'..'H', 'j'..'n', 'p'..'t', 'v'..'z', '*', '~'] ;
#  ^^^^ note this is a array ref, which you can build with whatever characters you want

my $d_arbenc = new Math::Base::Convert('10', $arb_enc); # from decimal
my $arbenc_d = new Math::Base::Convert( $arb_enc, '10'); # to decimal

# test it like this:
foreach ( "1", "123", 62, 64, 255, 65535, 100, 10000, 1000000 ) {
    my $status = eval {  $d_arbenc->cnv($_) }; # if error, $status will be empty, and error message will be in $@
    print "d_arbenc [$_] = [$status]\n";
    }

foreach ( "BD3F", "jjjnnnppp", "333", "bad string" ) {
    my $status = eval { $arbenc_d->cnv($_) }; # if error, $status will be empty, and error message will be in $@
    print "arbenc_d [$_] = [$status]\n";    
    }
insaner
  • 1,641
  • 16
  • 28