2012-03-07 13:24:10 -08:00
|
|
|
package DDG::Goodie::Base;
|
2014-08-20 11:45:33 -07:00
|
|
|
# ABSTRACT: convert numbers between arbitrary bases
|
2012-05-23 19:05:08 -07:00
|
|
|
|
2015-02-22 12:09:29 -08:00
|
|
|
use strict;
|
2012-03-07 13:24:10 -08:00
|
|
|
use DDG::Goodie;
|
2014-08-20 11:45:33 -07:00
|
|
|
|
2016-05-19 23:17:06 -07:00
|
|
|
use Math::Int2Base qw(int2base base2int);
|
2012-05-23 19:05:08 -07:00
|
|
|
use 5.010;
|
2014-08-14 16:32:12 -07:00
|
|
|
use bigint;
|
2012-03-07 13:24:10 -08:00
|
|
|
|
2012-03-12 08:57:25 -07:00
|
|
|
my %base_map = (
|
|
|
|
hex => 16,
|
|
|
|
hexadecimal => 16,
|
|
|
|
oct => 8,
|
|
|
|
octal => 8,
|
|
|
|
binary => 2,
|
2016-05-19 23:17:06 -07:00
|
|
|
dec => 10,
|
|
|
|
decimal => 10
|
2012-03-12 08:57:25 -07:00
|
|
|
);
|
2014-10-15 00:17:44 -07:00
|
|
|
my $map_keys = join '|', keys %base_map;
|
2012-05-23 19:05:08 -07:00
|
|
|
|
2016-05-19 23:36:01 -07:00
|
|
|
my %prefix_map = (
|
|
|
|
'0b' => 2,
|
|
|
|
'0x' => 16
|
|
|
|
);
|
|
|
|
my $prefix_keys = join '|', keys %prefix_map;
|
|
|
|
|
2012-04-15 18:31:26 -07:00
|
|
|
triggers any => 'base', keys %base_map;
|
2012-03-12 08:57:25 -07:00
|
|
|
|
2012-05-23 19:05:08 -07:00
|
|
|
zci answer_type => "conversion";
|
|
|
|
zci is_cached => 1;
|
|
|
|
|
2012-11-06 12:34:58 -08:00
|
|
|
primary_example_queries '255 in hex';
|
|
|
|
secondary_example_queries '255 in base 16', '42 in binary';
|
|
|
|
description 'convert a number to an arbitrary base';
|
|
|
|
name 'Base';
|
|
|
|
code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Base.pm';
|
|
|
|
category 'conversions';
|
|
|
|
topics 'math';
|
|
|
|
attribution web => [ 'http://perlgeek.de/blog-en', 'Moritz Lenz' ],
|
2015-01-07 10:37:42 -08:00
|
|
|
github => [ 'http://github.com/moritz', 'Moritz Lenz'];
|
2012-11-06 12:34:58 -08:00
|
|
|
|
|
|
|
|
2012-03-07 13:24:10 -08:00
|
|
|
handle query_clean => sub {
|
2016-05-19 23:36:01 -07:00
|
|
|
return unless /^(?<la>$prefix_keys)?(?<inp>[0-9A-Za-z]+)\s*((?:(?:in|as)\s+)?(?:(?<lt>$map_keys)|(?:base\s*(?<ln>[0-9]+)))\s+)?(?:(?:in|as|to)\s+)?(?:(?<rt>$map_keys)|(?:base\s*(?<rn>[0-9]+)))$/;
|
2016-05-19 23:17:06 -07:00
|
|
|
my $input = $+{'inp'};
|
|
|
|
my $from_base = 10;
|
2016-05-19 23:36:01 -07:00
|
|
|
if (defined $+{'la'}) {
|
|
|
|
$from_base = $prefix_map{$+{'la'}}
|
|
|
|
} elsif (defined $+{'ln'}) {
|
2016-05-19 23:17:06 -07:00
|
|
|
$from_base = $+{'ln'};
|
|
|
|
} elsif (defined $+{'lt'}) {
|
|
|
|
$from_base = $base_map{$+{'lt'}}
|
|
|
|
}
|
|
|
|
my $to_base = $+{'rn'} // $base_map{$+{'rt'}};
|
|
|
|
return if $to_base < 2 || $to_base > 36 || $from_base < 2 || $from_base > 36;
|
2016-05-19 23:36:01 -07:00
|
|
|
my $output;
|
2016-05-19 23:17:06 -07:00
|
|
|
eval { $output = convert_base($input, $from_base, $to_base) }; return if $@;
|
|
|
|
|
|
|
|
return "$input in base $to_base is $output",
|
2014-10-15 00:17:44 -07:00
|
|
|
structured_answer => {
|
2016-05-19 23:17:06 -07:00
|
|
|
input => ["$input"],
|
|
|
|
operation => "From base $from_base to base $to_base",
|
|
|
|
result => $output
|
2014-10-15 00:17:44 -07:00
|
|
|
};
|
2012-03-07 13:24:10 -08:00
|
|
|
};
|
|
|
|
|
2016-05-19 23:17:06 -07:00
|
|
|
sub convert_base {
|
|
|
|
my ($num, $from, $to) = @_;
|
2016-05-19 23:36:01 -07:00
|
|
|
return int2base( base2int( uc $num, $from), $to); # uc is necessary as Int2Base doesnt support lowercase
|
2016-05-19 23:17:06 -07:00
|
|
|
}
|
|
|
|
|
2012-03-07 13:24:10 -08:00
|
|
|
1;
|