File Coverage

blib/lib/Lingua/EUS/Numbers.pm
Criterion Covered Total %
statement 90 91 98.9
branch 46 52 88.4
condition 47 58 81.0
subroutine 9 9 100.0
pod 2 4 50.0
total 194 214 90.6


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; eval: (folding-mode 1); coding:utf-8; -*-
2              
3             package Lingua::EUS::Numbers;
4             # ABSTRACT: Number 2 word conversion in EUS.
5              
6             # {{{ use block
7              
8 5     5   151465 use 5.10.1;
  5         19  
9              
10 5     5   28 use warnings;
  5         10  
  5         264  
11 5     5   50 use strict;
  5         20  
  5         141  
12 5     5   27 use Carp;
  5         14  
  5         493  
13 5         7513 use vars qw(
14             @EXPORT_OK @ISA
15             %num2alpha
16 5     5   29 );
  5         9  
17             require Exporter;
18              
19             # }}}
20             # {{{ variables declaration
21              
22             @ISA = qw(Exporter);
23             our $VERSION = '0.2603230';
24              
25             @EXPORT_OK = qw(
26             %num2alpha
27             &cardinal2alpha
28             &ordinal2alpha
29             );
30              
31             # The Bask numeral system is vigesimal (base 20). So far, going to
32             # 999_999_999_999.
33              
34             %num2alpha = (
35             0 => 'zero',
36             1 => 'bat',
37             2 => 'bi',
38             3 => 'hiru',
39             4 => 'lau',
40             5 => 'bost',
41             6 => 'sei',
42             7 => 'zazpi',
43             8 => 'zortzi',
44             9 => 'bederatzi',
45             10 => 'hamar',
46             11 => 'hamaika',
47             12 => 'hamabi',
48             13 => 'hamahiru',
49             14 => 'hamalau',
50             15 => 'hamabost',
51             16 => 'hamasei',
52             17 => 'hamazazpi',
53             18 => 'hemezortzi',
54             19 => 'hemeretzi',
55             20 => 'hogei',
56             40 => 'berrogei',
57             60 => 'hirurogei',
58             80 => 'laurogei',
59             100 => 'ehun',
60             200 => 'berrehun',
61             300 => 'hirurehun',
62             400 => 'laurehun',
63             500 => 'bostehun',
64             600 => 'seiehun',
65             700 => 'zazpiehun',
66             800 => 'zortziehun',
67             900 => 'bederatziehun',
68             1000 => 'mila',
69             1000000 => 'milioi bat',
70             1000000000 => 'mila milioi'
71             );
72              
73             #Names for quantifiers, every block of 3 digits
74             #(thousands, millions, billions)
75             my %block2alpha = (
76             block1 => 'mila',
77             block2 => 'milioi',
78             block3 => 'mila milioi'
79             );
80              
81             # }}}
82              
83             #This function accepts an integer (scalar) as a parameter and
84             #returns a string (array), which is its Bask cardinal equivalent.
85             # {{{ cardinal2alpha
86              
87             sub cardinal2alpha {
88 318   50 318 1 1146428 my $orig_num = shift // return;
89 318         628 my @result = ();
90 318         656 my ( $thousands, $hundreds, $tens, $units );
91 318         562 my $num = $orig_num;
92              
93             #Input validation
94 318 100       1690 unless ( $num =~ /^\d+$/ ) {
95 5         835 carp "Entry $num not valid. Should be numeric characters only";
96 5         43 return;
97             }
98              
99 313 100 66     1615 if ( $num > 999_999_999_999 or $num < 0 ) {
100 1         224 carp "Entry $num not valid. Number should be an integer between 0 and 999,999,999,999";
101 1         9 return;
102             }
103              
104             #Handling special cases
105 312 100       697 return $num2alpha{0} if $num == 0;
106 310 100       1037 return $num2alpha{$num} if $num2alpha{$num};
107              
108 240         480 my $len = length($num);
109              
110             #Main logic: cutting number by block of 3 digits
111 240         604 while ( $len > 3 ) {
112              
113 166         437 $num = reverse($num);
114              
115             #Dealing with the part off the block(s) of three
116 166         626 my $extra_digits = substr( $num, int( ( $len - 1 ) / 3 ) * 3 );
117 166         304 $extra_digits = reverse($extra_digits);
118 166 100       551 push ( @result, triple_digit_handling($extra_digits) )
119             unless $extra_digits == 1;
120              
121             #Adding name for the quantifier
122 166         474 my $quantif = 'block' . ( int( ( $len - 1 ) / 3 ) );
123 166 100       727 push ( @result, $block2alpha{$quantif} ) unless $num =~ /000$/;
124              
125             #Special case for 1 million: adding the term for "one"
126 166 100 66     538 push ( @result, $num2alpha{1} ) if $len == 7 && $extra_digits == 1;
127              
128             #Adding "eta" after millions (except when there's no thousand)
129 166         410 my $whats_left = substr( reverse($num), length($extra_digits) );
130 166 100 100     932 if ( ( $len <= 8 and $len >= 7 )
      100        
      100        
131             && $whats_left != 0
132             && ( reverse($num) !~ /^[^0]000/ ) )
133             {
134 22         58 push ( @result, "eta" );
135             }
136              
137             #Adding 'eta' for hundreds, except when there are tens and/or units
138 166 100       397 if ( length($num) <= 6 ) {
139 78         507 ( $units, $tens, $hundreds, $thousands, my @rest ) =
140             split ( //, reverse($orig_num) );
141              
142 78 100 100     1055 if ( ( $hundreds != 0 && $tens == 0 && $units == 0 )
      100        
      100        
      100        
      100        
      100        
      100        
      66        
      66        
      66        
143             || ( $hundreds == 0 && ( $tens || $units ) ) && $num !~ /^0/
144             || ( $thousands == 0 && $hundreds == 0 && ( $tens || $units ) )
145             )
146             {
147 36         119 push ( @result, "eta" );
148             }
149             }
150              
151             #Dealing with the remaining digits
152 166         391 $num = reverse($num);
153 166         342 $num = substr( $num, length($extra_digits) );
154 166         489 $len = length($num);
155              
156             } #end while len > 3
157              
158 240 50       669 if ( $len <= 3 ) {
159 240         540 push ( @result, triple_digit_handling($num) );
160 240         1439 return "@result";
161             }
162             }
163              
164             # }}}
165              
166             #This function takes an integer (scalar) as a parameter, which is
167             #a 3-digit number or less, and returns a string (array), which is
168             #its Bask equivalent.
169             # {{{ triple_digit_handling
170              
171             sub triple_digit_handling {
172 352     352 0 736 my $num = shift;
173 352         644 my @result = ();
174 352         668 my ( $hundreds, $tens, $units, @tens_n_units );
175              
176             #Handling exceptional cases
177 352 50 33     1462 return if $num > 999 || $num < 0;
178 352 100       863 return if $num == 0;
179 256 100       737 return $num2alpha{$num} if $num2alpha{$num};
180              
181 214         419 my $len = length($num);
182              
183             #Handling 2-digit numbers
184 214 100       494 if ( $len == 2 ) {
185 152         980 ( $tens, $units ) = split ( //, sprintf( "%02d", $num ) );
186 152         454 @result = double_digit_handling( $tens, $units );
187 152         550 return @result;
188             }
189              
190             #Handling 3-digit numbers
191 62 50       211 if ( $len == 3 ) {
192 62         418 ( $hundreds, $tens, $units ) = split ( //, sprintf( "%03d", $num ) );
193 62 100       206 unless ( $hundreds == 0 ) {
194 28         64 $hundreds *= 100;
195 28         86 push ( @result, $num2alpha{$hundreds} );
196 28 50 66     135 push ( @result, "eta" ) if $tens || $units;
197             }
198              
199 62         173 @tens_n_units = double_digit_handling( $tens, $units );
200 62         126 push ( @result, @tens_n_units );
201 62         215 return @result;
202             }
203              
204             }
205              
206             # }}}
207              
208             #This function takes two integers (scalars) as parameters (tens and units)
209             #and returns a string (array), which is their Bask equivalent.
210             # {{{ double_digit_handling
211              
212             sub double_digit_handling {
213 214     214 0 409 my $diz = shift;
214 214         378 my $unit = shift;
215 214         589 my $num = "$diz$unit";
216 214         376 my @result;
217              
218             #Handling exceptional cases
219 214 50       575 return if $num == 0;
220              
221 214 100       613 return $num2alpha{$num} if $num2alpha{$num};
222              
223 192 100       510 return $num2alpha{$unit} unless $diz;
224              
225             #Dealing with base 20
226 154 100       649 if ( $diz =~ /[3579]/ ) {
227 80         196 $diz -= 1;
228 80         169 $unit += 10;
229             }
230 154         323 $diz = $diz * 10;
231              
232 154 50       339 if ($unit) { push ( @result, "$num2alpha{$diz}ta" ); }
  154         642  
233 0         0 else { push ( @result, $num2alpha{$diz} ); }
234 154         437 push ( @result, $num2alpha{$unit} );
235              
236 154         616 return @result;
237             }
238              
239             # }}}
240              
241             #This function accepts an integer (scalar) as a parameter and
242             #returns a string (array), which is its Bask ordinal equivalent.
243             # {{{ ordinal2alpha
244              
245             sub ordinal2alpha {
246 162   50 162 1 516569 my $num = shift // return;
247 162         333 my @result;
248              
249             #Handling special cases
250 162 100       1036 return unless $num =~ /^\d+$/;
251 157 100 66     953 return if ( $num < 0 || $num > 999_999_999_999 );
252 156 100       424 return "lehenengo" if $num == 1;
253              
254 155         425 push ( @result, join ( '', cardinal2alpha($num), "garren" ) );
255 155         587 return "@result";
256             }
257              
258             # }}}
259              
260             1;
261             __END__