From: mgfrank@avernus.com (Marc G. Frank)
Newsgroups: comp.lang.perl,sci.classics
Subject: SCRIPT: Roman numeral conversion
Date: 3 Sep 92 00:26:39 GMT
Article-I.D.: avernus.1992Sep3.002639.8834
Organization: Maryland Appreciation Society


How many times have you said:

"Gee, perl looks pretty neat.  Too bad it doesn't handle Roman numerals."

or:

"DAMN!  If perl's such a great language, then why the hell can't it use
Roman numerals?"

or:

"I'd like to recommend perl, sir, but I'm afraid I can't until the Roman
numeral matter is resolved."

or:

"I'd send Larry lots and lots of money for writing such a useful
utility, but I won't because it doesn't do Roman numerals."

vel:

"Stercus!  Cur non margarita potest numeros Romanos computare?'

Hundreds if not thousands of times, I reckon.  Well, relax, because
the wait is over!  Included below is a package to convert to and from
Roman numerals.

While ator, the routine to convert to Roman numerals, could be
marginally useful on occasion (page numbers, perhaps), as far as I can
tell rtoa, which converts from Roman numerals, is useless unless you
want to use it to cheat on^H^H^H^H^H^H^H^Hcheck your Latin I homework.
I pretty much just wrote that one for the fun of it.  Note that this
package hasn't been thoroughly tested (it converts the numbers I need it
to convert, so hey, why test further?), so you might not want to use it
for mission-critical applications.  If you *have* a mission-critical
application that needs Roman numeral conversion, then perhaps it's time
to *seriously* reconsider your mission.  :-)

Also included is testromn.pl.  Feed it either Arabic or Roman numerals
on stdin, and it spits out the other on stdout.  Rather useful for
checking Latin I homework.  Other documentation is to found in the
comments in roman.pl.

Enjoy.  BTW, this article is crossposted(!), so if you follow up be sure
to edit the Newsgroups: line accordingly.


+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| Marc G. Frank                                  mgfrank@avernus.com |
|                   I'd rather be in Eldersburg.                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	roman.pl
#	testromn.pl
#
echo x - roman.pl
sed 's/^X//' >roman.pl << 'END-of-roman.pl'
X#
X# roman.pl -- package to convert to and from Roman numerals
X#
X# Marc G. Frank
X# mgfrank@avernus.com
X# Written August , 992
X# Author got around to documenting it September 2, 992
X#
X# This amazingly useful package makes a modest attempt to convert between
X# Roman and Arabic numerals.  It will convert Arabic integers to Roman
X# numerals in the range  <= x <= 4999, after which things get a bit messy:
X# the Roman numerals have to have bars over them (or something like that)
X# which isn't easily representable in ASCII.  If you feed ator something
X# that isn't an integer in this range it returns ''.
X#
X# Converting the other way around is a bit trickier as far as error
X# detection is concerned, so rtoa doesn't do much of it.  Suffice it to
X# say that if you feed it a valid Roman numeral you'll get the Arabic
X# equivalent back.  If you feed it something that obviously isn't a
X# Roman numeral it returns ''.  If you feed it an invalid Roman numeral
X# (like XXCMDLM) you'll get something back, but if the input isn't valid
X# there's no reason the output should be.  :-)
X#
X# Usage:
X# require "roman.pl";
X# $something = &ator($some_number);
X# $something_else = &rtoa($some_roman_numeral);
X#
X# Note that Roman numerals are returned in uppercase.  If you don't like this,
X# use tr on the resulting string.
X#
X# Bugs to mgfrank@avernus.com
X
X
Xpackage roman;
X
X
Xsub main'ator {          # Convert Arabic integers to Roman numerals
X  local($n) = @_;
X  local($i, $roman);
X  return '' if ($n =~ /[\D.Ee]/ || $n <  || $n > 4999); # Rudimentary error-
X  local(@numerals) = (I,X,C,M);                          # checking
X
X  # I'm bad at math so I found it easier to do the conversion stringly.  This
X  # bit converts the Arabic numeral in each position to the corresponding
X  # number of equivalent Roman numerals.  That is, if the number to be
X  # converted is 992, the 9 in the hundreds place is converted to CCCCCCCCC.
X
X  $n = reverse($n);
X  for($i = length($n) -  ; $i >= 0 ; $i--) {
X    $roman .= @numerals[$i] x substr($n, $i, );
X  }
X
X  # Once that's been done, all that's left to do is convert strings like
X  # CCCCCCCCC to strings like XC.
X
X  $roman =~ s/C{9}/CM/;
X  $roman =~ s/C{5}/D/;
X  $roman =~ s/C{4}/CD/;
X  $roman =~ s/X{5}/L/;
X  $roman =~ s/X{4}/XL/;
X  $roman =~ s/LXL/XC/;
X  $roman =~ s/I{9}/IX/;
X  $roman =~ s/I{5}/V/;
X  $roman =~ s/I{4}/IV/;
X  $roman;
X}
X
X
X
Xsub main'rtoa {          # Convert Roman numerals into Arabic
X  local($n) = @_;
X  $n =~ tr/mdclxvi/MDCLXVI/; # Canonicalize to uppercase
X  return '' if $n =~ /[^MDCLXVI]/; # *Very* rudimentary error-checking
X  local($arabic, $i);
X  local(%numerals) = ('M', 000,
X		      'D', 500,
X		      'C', 00,
X		      'L', 50,
X		      'X', 0,
X		      'V', 5,
X		      'I', );
X
X  # Do the reverse of before.  Translate strings like XC to strings like
X  # CCCCCCCCC.
X
X  $n =~ s/CM/CCCCCCCCC/;
X  $n =~ s/CD/CCCC/;
X  $n =~ s/XL/XXXX/;
X  $n =~ s/XC/XXXXXXXXX/;
X  $n =~ s/IX/IIIIIIIII/;
X  $n =~ s/IV/IIII/;
X
X  # Now just add the value of every character in the string to the result.
X
X  for($i = 0 ; $i < length($n) ; $i++) {
X    $arabic += $numerals{substr($n, $i, )};
X  }
X  $arabic;
X}
X
X; # Return an end-of-package true.
END-of-roman.pl
echo x - testromn.pl
sed 's/^X//' >testromn.pl << 'END-of-testromn.pl'
X#!/usr/bin/perl
X
Xrequire "roman.pl";
X
Xwhile(<STDIN>) {
X    chop;
X    if(/\d+/) { print &ator($_), "\n"; }
X    else { print &rtoa($_), "\n"; }
X}
END-of-testromn.pl
exit


+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| Marc G. Frank                                  mgfrank@avernus.com |
|                   I'd rather be in Eldersburg.                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Newsgroups: comp.lang.perl,alt.security