#!/usr/bin/perl -w
use strict;
sub arabic;# Changes a Roman Numeral to an Arabic Number
# input Roman Numeral < 4000,
# output Arabic Number as string.
sub isroman; # Check if string is Roman Numeral and return true if so.
my $roman_numeral = "MMCXLII";
my $result = "";
my $digit = "";
my $last_digit = "";
my $roman_digit = "";
# Hash table follows for converting A Roman Numeral Digit to an
# Arabic Number.
my %roman2arabic = qw(I 1 V 5 X 10 L 50 C 100 D 500 M 1000);
sub isroman { # This will return True as long the Roman Numeral
# contains only valid letters and is less than
# 4000, i.e. I TO MMMCMXCIX
# First we check if it begins with 0 to 3 M's.
# then D or 0 to 3 C's, or contains CD or CM,
# then L or 0 to 3 X's, or contains XL or XC,
# then V or 0 to 3 I's, or contains IV or IX.
# We do this ignoring case and making the expression
# more readable using white space as dentoed
# by the "ix" at the end.
## Perl 5 From O'Reilly book, check for Roman Numeral
# $str =~ m/ ^ m* (?:d?c{0,3}|c[dm]) (?:l?x{0,3}|x[lc]) (?:v?i{0,3}|i[vx]) $ /ix;
## End O'Reilly Perl Cookbook Quote
my($arg) = shift;
$arg ne '' and
$arg =~ /^(?: M{0,3})
(?: D?C{0,3} | C[DM])
(?: L?X{0,3} | X[LC])
(?: V?I{0,3} | I[VX])$/ix;
}
sub arabic { # Input Roman Numeral , Return Arabic Number
my($arg) = shift; # Get Input of Roman Numeral
isroman $arg or return undef; # Check it or return undefined, leaving # module
my $last_digit = 1000; # The last digit we will write is the
# thousands place if it is there.
# M would map to 1000 as the last_digit.
my $arabic_number = 0; # initialize to meaningless value
# note there is no zero in Roman Numerals so
# we will never get zero as our Arabic Number.
foreach (split (//, uc $arg)){ # Loop through the Roman Numeral
#starting with the left most Roman Numeral Digit, i.e. M.
# We use the Hash Table to look up the corresponding Arabic Number
# for the Roman Numeral. At first glance it looks like we could
# just use these two lines:
# $last_digit = $digit;
# $arabic_number = $arabic_number + $last_digit;
# This will loop through each Roman Numeral and sum it to the
# previous total. However, pay attention what happens when we
# encounter XL for 40. We would interpret this as 60, we fix this
# by noting here the last_digit X is less than L . Therefore we
# put in the correction of subtracting out twice the last digit.
# This gives 60 - 20 (2 * X) yielding 40 the proper amount.
# This was the trickiest part of the algorithm.
# Note, I have defaulted to the more readable perl code instead
# of combining everything in a line with the += and -= operators.
my $digit = $roman2arabic{$_};
if ($last_digit < $digit)
{$arabic_number = $arabic_number - (2 * $last_digit);}
$last_digit = $digit;
$arabic_number = $arabic_number + $last_digit;
}
$arabic_number ;
}
# End Subroutine Section
#
# Main Section
$result = arabic($roman_numeral);
print "This is arabic number: $result \n";
print "for roman numeral: $roman_numeral \n";
# End Main Section
exit;