File Coverage

blib/lib/Lingua/EUS/Num2Word.pm
Criterion Covered Total %
statement 102 105 97.1
branch 46 52 88.4
condition 47 58 81.0
subroutine 13 15 86.6
pod 3 6 50.0
total 211 236 89.4


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::Num2Word;
4             # ABSTRACT: Converts numbers into Bask (Euskara).
5              
6 5     5   162667 use 5.16.0;
  5         22  
7 5     5   2816 use utf8;
  5         1581  
  5         35  
8 5     5   182 use warnings;
  5         14  
  5         279  
9              
10             # {{{ use block
11              
12 5     5   31 use Carp;
  5         17  
  5         582  
13 5     5   5187 use Export::Attrs;
  5         63945  
  5         35  
14              
15             # }}}
16             # {{{ variables declaration
17              
18             our $VERSION = '0.2603300';
19              
20             # The Bask numeral system is vigesimal (base 20). So far, going to
21             # 999_999_999_999.
22              
23 5     5   707 our %num2alpha :Export = (
  5         17  
  5         32  
24             0 => 'zero',
25             1 => 'bat',
26             2 => 'bi',
27             3 => 'hiru',
28             4 => 'lau',
29             5 => 'bost',
30             6 => 'sei',
31             7 => 'zazpi',
32             8 => 'zortzi',
33             9 => 'bederatzi',
34             10 => 'hamar',
35             11 => 'hamaika',
36             12 => 'hamabi',
37             13 => 'hamahiru',
38             14 => 'hamalau',
39             15 => 'hamabost',
40             16 => 'hamasei',
41             17 => 'hamazazpi',
42             18 => 'hemezortzi',
43             19 => 'hemeretzi',
44             20 => 'hogei',
45             40 => 'berrogei',
46             60 => 'hirurogei',
47             80 => 'laurogei',
48             100 => 'ehun',
49             200 => 'berrehun',
50             300 => 'hirurehun',
51             400 => 'laurehun',
52             500 => 'bostehun',
53             600 => 'seiehun',
54             700 => 'zazpiehun',
55             800 => 'zortziehun',
56             900 => 'bederatziehun',
57             1000 => 'mila',
58             1000000 => 'milioi bat',
59             1000000000 => 'mila milioi'
60             );
61              
62             #Names for quantifiers, every block of 3 digits
63             #(thousands, millions, billions)
64             my %block2alpha = (
65             block1 => 'mila',
66             block2 => 'milioi',
67             block3 => 'mila milioi'
68             );
69              
70             # }}}
71              
72             #This function accepts an integer (scalar) as a parameter and
73             #returns a string (array), which is its Bask cardinal equivalent.
74             # {{{ cardinal2alpha
75              
76 5     5 0 2959 sub num2eus_cardinal :Export { goto &cardinal2alpha }
  5     0   12  
  5         38  
  0         0  
77              
78             sub cardinal2alpha :Export {
79 318   50 318 1 1346991 my $orig_num = shift // return;
80 318         546 my @result = ();
81 318         591 my ( $thousands, $hundreds, $tens, $units );
82 318         486 my $num = $orig_num;
83              
84             #Input validation
85 318 100       1566 unless ( $num =~ /^\d+$/ ) {
86 5         762 carp "Entry $num not valid. Should be numeric characters only";
87 5         41 return;
88             }
89              
90 313 100 66     1400 if ( $num > 999_999_999_999 or $num < 0 ) {
91 1         132 carp "Entry $num not valid. Number should be an integer between 0 and 999,999,999,999";
92 1         27 return;
93             }
94              
95             #Handling special cases
96 312 100       610 return $num2alpha{0} if $num == 0;
97 310 100       1033 return $num2alpha{$num} if $num2alpha{$num};
98              
99 240         399 my $len = length($num);
100              
101             #Main logic: cutting number by block of 3 digits
102 240         569 while ( $len > 3 ) {
103              
104 166         854 $num = reverse($num);
105              
106             #Dealing with the part off the block(s) of three
107 166         525 my $extra_digits = substr( $num, int( ( $len - 1 ) / 3 ) * 3 );
108 166         267 $extra_digits = reverse($extra_digits);
109 166 100       456 push ( @result, triple_digit_handling($extra_digits) )
110             unless $extra_digits == 1;
111              
112             #Adding name for the quantifier
113 166         588 my $quantif = 'block' . ( int( ( $len - 1 ) / 3 ) );
114 166 100       734 push ( @result, $block2alpha{$quantif} ) unless $num =~ /000$/;
115              
116             #Special case for 1 million: adding the term for "one"
117 166 100 66     471 push ( @result, $num2alpha{1} ) if $len == 7 && $extra_digits == 1;
118              
119             #Adding "eta" after millions (except when there's no thousand)
120 166         340 my $whats_left = substr( reverse($num), length($extra_digits) );
121 166 100 100     815 if ( ( $len <= 8 and $len >= 7 )
      100        
      100        
122             && $whats_left != 0
123             && ( reverse($num) !~ /^[^0]000/ ) )
124             {
125 22         55 push ( @result, "eta" );
126             }
127              
128             #Adding 'eta' for hundreds, except when there are tens and/or units
129 166 100       362 if ( length($num) <= 6 ) {
130 78         408 ( $units, $tens, $hundreds, $thousands, my @rest ) =
131             split ( //, reverse($orig_num) );
132              
133 78 100 100     957 if ( ( $hundreds != 0 && $tens == 0 && $units == 0 )
      100        
      100        
      100        
      100        
      100        
      100        
      66        
      66        
      66        
134             || ( $hundreds == 0 && ( $tens || $units ) ) && $num !~ /^0/
135             || ( $thousands == 0 && $hundreds == 0 && ( $tens || $units ) )
136             )
137             {
138 36         113 push ( @result, "eta" );
139             }
140             }
141              
142             #Dealing with the remaining digits
143 166         321 $num = reverse($num);
144 166         322 $num = substr( $num, length($extra_digits) );
145 166         378 $len = length($num);
146              
147             } #end while len > 3
148              
149 240 50       565 if ( $len <= 3 ) {
150 240         593 push ( @result, triple_digit_handling($num) );
151 240         1182 return "@result";
152             }
153 5     5   4835 }
  5         34  
  5         53  
154              
155             # }}}
156              
157             #This function takes an integer (scalar) as a parameter, which is
158             #a 3-digit number or less, and returns a string (array), which is
159             #its Bask equivalent.
160             # {{{ triple_digit_handling
161              
162             sub triple_digit_handling {
163 352     352 0 628 my $num = shift;
164 352         567 my @result = ();
165 352         525 my ( $hundreds, $tens, $units, @tens_n_units );
166              
167             #Handling exceptional cases
168 352 50 33     1257 return if $num > 999 || $num < 0;
169 352 100       774 return if $num == 0;
170 256 100       688 return $num2alpha{$num} if $num2alpha{$num};
171              
172 214         322 my $len = length($num);
173              
174             #Handling 2-digit numbers
175 214 100       478 if ( $len == 2 ) {
176 152         862 ( $tens, $units ) = split ( //, sprintf( "%02d", $num ) );
177 152         474 @result = double_digit_handling( $tens, $units );
178 152         501 return @result;
179             }
180              
181             #Handling 3-digit numbers
182 62 50       206 if ( $len == 3 ) {
183 62         386 ( $hundreds, $tens, $units ) = split ( //, sprintf( "%03d", $num ) );
184 62 100       202 unless ( $hundreds == 0 ) {
185 28         51 $hundreds *= 100;
186 28         105 push ( @result, $num2alpha{$hundreds} );
187 28 50 66     151 push ( @result, "eta" ) if $tens || $units;
188             }
189              
190 62         181 @tens_n_units = double_digit_handling( $tens, $units );
191 62         183 push ( @result, @tens_n_units );
192 62         197 return @result;
193             }
194              
195             }
196              
197             # }}}
198              
199             #This function takes two integers (scalars) as parameters (tens and units)
200             #and returns a string (array), which is their Bask equivalent.
201             # {{{ double_digit_handling
202              
203             sub double_digit_handling {
204 214     214 0 355 my $diz = shift;
205 214         351 my $unit = shift;
206 214         431 my $num = "$diz$unit";
207 214         306 my @result;
208              
209             #Handling exceptional cases
210 214 50       519 return if $num == 0;
211              
212 214 100       515 return $num2alpha{$num} if $num2alpha{$num};
213              
214 192 100       519 return $num2alpha{$unit} unless $diz;
215              
216             #Dealing with base 20
217 154 100       598 if ( $diz =~ /[3579]/ ) {
218 80         167 $diz -= 1;
219 80         159 $unit += 10;
220             }
221 154         306 $diz = $diz * 10;
222              
223 154 50       416 if ($unit) { push ( @result, "$num2alpha{$diz}ta" ); }
  154         502  
224 0         0 else { push ( @result, $num2alpha{$diz} ); }
225 154         472 push ( @result, $num2alpha{$unit} );
226              
227 154         534 return @result;
228             }
229              
230             # }}}
231              
232             #This function accepts an integer (scalar) as a parameter and
233             #returns a string (array), which is its Bask ordinal equivalent.
234             # {{{ ordinal2alpha
235              
236             sub ordinal2alpha :Export {
237 162   50 162 1 410373 my $num = shift // return;
238 162         280 my @result;
239              
240             #Handling special cases
241 162 100       974 return unless $num =~ /^\d+$/;
242 157 100 66     833 return if ( $num < 0 || $num > 999_999_999_999 );
243 156 100       359 return "lehenengo" if $num == 1;
244              
245 155         388 push ( @result, join ( '', cardinal2alpha($num), "garren" ) );
246 155         618 return "@result";
247 5     5   4721 }
  5         14  
  5         23  
248              
249             # }}}
250              
251              
252             # {{{ capabilities declare supported features
253              
254             sub capabilities {
255             return {
256 0     0 1   cardinal => 1,
257             ordinal => 0,
258             };
259             }
260              
261             # }}}
262             1;
263             __END__