line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Number::Convert::Roman; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Number::Convert::Roman - Roman-Arabic numeral converter |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# Copyright (c) 2015 José Santos. All rights reserved. |
6
|
|
|
|
|
|
|
# This program is free software. It can be redistributed and/or modified under |
7
|
|
|
|
|
|
|
# the same terms as Perl itself. |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
19192
|
use 5.006; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
33
|
|
10
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
11
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
691
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my %ROMAN_ARABIC = ('I' => 1, 'V' => 5, 'X' => 10, 'L' => 50, |
16
|
|
|
|
|
|
|
'C' => 100, 'D' => 500, 'M' => 1000); |
17
|
|
|
|
|
|
|
my %ARABIC_ROMAN = map { $ROMAN_ARABIC{$_} => $_ } keys %ROMAN_ARABIC; |
18
|
|
|
|
|
|
|
my ($THOUSANDS_OPEN, $THOUSANDS_CLOSE) = ('(', ')'); |
19
|
|
|
|
|
|
|
|
20
|
0
|
|
|
0
|
1
|
|
sub new { bless {}, shift; } |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub arabic { |
23
|
0
|
|
|
0
|
1
|
|
shift; |
24
|
0
|
|
|
|
|
|
my @roman = split //, shift; |
25
|
0
|
|
|
|
|
|
my ($number, $sum, $last, $thousands) = (0, 0, 0, 0); |
26
|
0
|
|
|
|
|
|
for (my $i = $#roman; $i >= 0; $i--) { |
27
|
0
|
0
|
|
|
|
|
if ($roman[$i] !~ /[$THOUSANDS_CLOSE$THOUSANDS_OPEN]/) { |
|
|
0
|
|
|
|
|
|
28
|
0
|
|
|
|
|
|
$number = $ROMAN_ARABIC{$roman[$i]}; |
29
|
0
|
0
|
|
|
|
|
$sum += ($number >= $last ? 1 : -1) * ($number * 1000 ** $thousands); |
30
|
0
|
|
|
|
|
|
$last = $number; |
31
|
|
|
|
|
|
|
} elsif ($roman[$i] eq $THOUSANDS_CLOSE) { |
32
|
0
|
|
|
|
|
|
$last = 0; |
33
|
0
|
|
|
|
|
|
$thousands++; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
} |
36
|
0
|
|
|
|
|
|
$sum; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub roman { |
40
|
0
|
|
|
0
|
1
|
|
shift; |
41
|
0
|
|
|
|
|
|
my ($i, @arabic) = (-1, split //, shift); |
42
|
0
|
0
|
|
|
|
|
my @numbers = map { $i++; $_ > 0 ? $_ . '0' x ($#arabic - $i) : () } @arabic; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
43
|
0
|
|
|
|
|
|
my ($prefix, $x, $y, $first, $thousands, $zerofill); |
44
|
|
|
|
|
|
|
# break each number using roman logic and underscore prefix each power of 1000 |
45
|
|
|
|
|
|
|
# e.g. 1000 -> _1; 3000 -> _1, _1, _1; 4000 -> _1, _5; 5000000 -> __5 |
46
|
0
|
|
|
|
|
|
for ($i = 0; $i <= $#numbers; $i++) { |
47
|
0
|
|
|
|
|
|
$prefix = ''; |
48
|
0
|
|
|
|
|
|
$first = substr $numbers[$i], 0, 1; |
49
|
0
|
|
|
|
|
|
$thousands = int(log($numbers[$i] / $first) / log(1000)); |
50
|
0
|
|
|
|
|
|
$prefix = '_' x $thousands; |
51
|
0
|
|
|
|
|
|
$numbers[$i] /= 1000 ** $thousands; |
52
|
0
|
|
|
|
|
|
$zerofill = '0' x ((length $numbers[$i]) - 1); |
53
|
0
|
0
|
0
|
|
|
|
if ($first == 1 || $first == 5) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
54
|
0
|
|
|
|
|
|
$numbers[$i] = $prefix . $numbers[$i]; |
55
|
|
|
|
|
|
|
} elsif ($first >= 2 && $first <= 3) { # replace [2-3]0* by 2-3 x _+10* |
56
|
0
|
|
|
|
|
|
splice @numbers, $i, 1; |
57
|
0
|
|
|
|
|
|
for (1 .. $first) { |
58
|
0
|
|
|
|
|
|
splice @numbers, $i, 0, $prefix . 1 . $zerofill; |
59
|
|
|
|
|
|
|
} |
60
|
0
|
|
|
|
|
|
$i += $first - 1; |
61
|
|
|
|
|
|
|
} elsif ($first == 4) { # replace 40* by 10* and 50* |
62
|
0
|
|
|
|
|
|
splice @numbers, $i, 1; |
63
|
0
|
|
|
|
|
|
splice @numbers, $i++, 0, $prefix . 1 . $zerofill, $prefix . 5 . $zerofill; |
64
|
|
|
|
|
|
|
} elsif ($first >= 6 and $first <= 8) { # replace [6-8]0* by 50* + 1-3 x +10* |
65
|
0
|
|
|
|
|
|
splice @numbers, $i, 1; |
66
|
0
|
|
|
|
|
|
for (6 .. $first) { |
67
|
0
|
|
|
|
|
|
splice @numbers, $i, 0, $prefix . 1 . $zerofill; |
68
|
|
|
|
|
|
|
} |
69
|
0
|
|
|
|
|
|
splice @numbers, $i, 0, $prefix . 5 . $zerofill; |
70
|
0
|
|
|
|
|
|
$i += ($first - 5); |
71
|
|
|
|
|
|
|
} elsif ($first == 9) { # replace 90* by 10* and 50* |
72
|
0
|
|
|
|
|
|
splice @numbers, $i, 1; |
73
|
0
|
|
|
|
|
|
splice @numbers, $i++, 0, $prefix . 1 . $zerofill, $prefix . 10 . $zerofill; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
# replace each underscore prefixed number by its parenthesis surrounded version |
77
|
|
|
|
|
|
|
# e.g. _1 -> (I); _1, _1, _1 -> (III); _1, _5 -> (IV); __5 -> ((V)) |
78
|
0
|
|
|
|
|
|
my ($result, $previous_level, $level, $number) = ('', -1, 0, ''); |
79
|
0
|
|
|
|
|
|
for (@numbers) { |
80
|
0
|
|
|
|
|
|
($prefix, $number) = m/(_*)(.+)/; |
81
|
0
|
|
|
|
|
|
$level = length $prefix; |
82
|
0
|
0
|
|
|
|
|
if ($level != $previous_level) { |
83
|
0
|
0
|
|
|
|
|
if ($level < $previous_level) { |
|
|
0
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
$result .= $THOUSANDS_CLOSE x ($previous_level - $level); |
85
|
|
|
|
|
|
|
} elsif ($level > $previous_level) { |
86
|
0
|
|
|
|
|
|
$result .= '(' x $level; |
87
|
|
|
|
|
|
|
} |
88
|
0
|
|
|
|
|
|
$previous_level = $level; |
89
|
|
|
|
|
|
|
} |
90
|
0
|
|
|
|
|
|
$result .= $ARABIC_ROMAN{$number}; |
91
|
|
|
|
|
|
|
} |
92
|
0
|
0
|
|
|
|
|
if ($level eq $previous_level) { |
93
|
0
|
|
|
|
|
|
$result .= $THOUSANDS_CLOSE x $level; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
# replace all (I), (II) and (III) by M, MM and MMM, respectively |
96
|
0
|
|
|
|
|
|
$result =~ s/\((I+)\)/'M' x length $1/ge; |
|
0
|
|
|
|
|
|
|
97
|
0
|
|
|
|
|
|
$result; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
__END__ |