#!/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;