#!/usr/bin/perl # # Tests on Roman numbers modules # Test on Unicode characters and the W3C specification use strict; use warnings; use Math::Roman; use Convert::Number::Roman; # U+2160 = o20540 = 8544, U+2170 = 0o20560 = 8560 Math::Roman::tokens( "\x{2160}", 1, "\x{2161}", 2, "\x{2162}", 3, "\x{2163}", 4, "\x{2164}", 5, "\x{2165}", 6, "\x{2166}", 7, "\x{2167}", 8, "\x{2168}", 9, "\x{2169}", 10, "\x{216A}", 11, "\x{216B}", 12, "\x{2169}\x{2162}", 13, "\x{2169}\x{2163}", 14, "\x{2169}\x{2164}", 15, "\x{2169}\x{2165}", 16, "\x{2169}\x{2166}", 17, "\x{2169}\x{2167}", 18, "\x{2169}\x{2168}", 19, "\x{2169}\x{2169}", 20, "\x{2169}\x{216A}", 21, "\x{2169}\x{216B}", 22, "\x{2169}\x{2169}\x{2162}", 23, "\x{2169}\x{2169}\x{2163}", 24, "\x{2169}\x{2169}\x{2164}", 25, "\x{2169}\x{2169}\x{2165}", 26, "\x{2169}\x{2169}\x{2166}", 27, "\x{2169}\x{2169}\x{2167}", 28, "\x{2169}\x{2169}\x{2168}", 29, "\x{2169}\x{2169}\x{2169}", 30, "\x{2169}\x{2169}\x{216A}", 31, "\x{2169}\x{2169}\x{216B}", 32, "\x{2169}\x{2169}\x{2169}\x{2162}", 33, "\x{2169}\x{2169}\x{2169}\x{2163}", 34, "\x{2169}\x{2169}\x{2169}\x{2164}", 35, "\x{2169}\x{2169}\x{2169}\x{2165}", 36, "\x{2169}\x{2169}\x{2169}\x{2166}", 37, "\x{2169}\x{2169}\x{2169}\x{2167}", 38, "\x{2169}\x{2169}\x{2169}\x{2168}", 39, "\x{2169}\x{216C}", 40, "\x{216C}", 50, "\x{2169}\x{216D}", 90, "\x{216D}", 100, "\x{216D}\x{216E}", 400, "\x{216E}", 500, "\x{216D}\x{216F}", 900, "\x{216F}", 1000); for my $n (1..3999) { my $mod = $n % 50; my $cnr = Convert::Number::Roman->new($n); my $mr = Math::Roman->new($n); if ($cnr->convert ne $mr) { print "Error 1 for $n\n"; } if ($mr->as_number != $n) { print "Error 2 for $n\n"; } }

For the argument to `tokens`, the initial idea was
to enumerate all Unicode values from "I" to "XII", with their 1 to 12
values. It did not work, because 13 was converted to `\x{216B}\x{2160}`, that is "XII" + "I"
instead of `\x{2169}\x{2162}`, that is, "X" + "III".
So I had to add this pair of values. Then the same problem arose
with 14, and then 15, and so on, until 40. Starting with
40, I could at last leave some holes.

For the sake of comparison, here is a script in which I decided not
to use `\x{216A}` for "XI" and `\x{216B}` for "XII".
Like the script above, we compare the output of `Math::Roman`
with the output of `Convert::Number::Roman`, after
having replaced "XI" by "X" + "I" and "XII" by "X" + "II".
As you can see, it is much simpler and much more concise.

#!/usr/bin/perl # # Tests on Roman numbers modules # Test on Unicode characters and the W3C specification, while ignoring the characters for XI and XII use strict; use warnings; use Math::Roman; use Convert::Number::Roman; # U+2160 = o20540 = 8544, U+2170 = 0o20560 = 8560 Math::Roman::tokens( "\x{2160}", 1, "\x{2161}", 2, "\x{2162}", 3, "\x{2163}", 4, "\x{2164}", 5, "\x{2165}", 6, "\x{2166}", 7, "\x{2167}", 8, "\x{2168}", 9, "\x{2169}", 10, "\x{2169}\x{216C}", 40, "\x{216C}", 50, "\x{2169}\x{216D}", 90, "\x{216D}", 100, "\x{216D}\x{216E}", 400, "\x{216E}", 500, "\x{216D}\x{216F}", 900, "\x{216F}", 1000); for my $n (1..3999) { my $mod = $n % 50; my $cnr = Convert::Number::Roman->new($n); my $cnr_str = $cnr->convert; $cnr_str =~ s/\x{216A}/\x{2169}\x{2160}/g; $cnr_str =~ s/\x{216B}/\x{2169}\x{2161}/g; my $mr = Math::Roman->new($n); if ($cnr_str ne $mr) { print "Error 1 for $n\n"; } if ($mr->as_number != $n) { print "Error 2 for $n\n"; } }

Note that these two scripts can read and produce all valid numbers. But they do not catch invalid numbers. This is left as a (painful) exercise to the reader.

© 2011 Jean Forget and Les Mongueurs de Perl. The code in this file is free software; you can redistribute it or modify it under the same terms as Perl 5.10.0. The text is under Creative Commons license with paternity, no modification.

Main page Return to text