File Coverage

blib/lib/Lingua/IND/Nums2Words.pm
Criterion Covered Total %
statement 82 82 100.0
branch 32 38 84.2
condition 50 75 66.6
subroutine 15 15 100.0
pod 9 9 100.0
total 188 219 85.8


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; mode:folding -*-
2              
3             package Lingua::IND::Nums2Words;
4             # ABSTRACT: Number 2 word conversion in IND.
5              
6             # {{{ use block
7              
8 1     1   26462 use 5.10.1;
  1         4  
  1         43  
9 1     1   6 use strict;
  1         1  
  1         41  
10 1     1   5 use warnings;
  1         6  
  1         29  
11              
12 1     1   973 use Perl6::Export::Attrs;
  1         11794  
  1         8  
13              
14             # }}}
15             # {{{ variables declaration
16              
17             our $VERSION = 0.0708;
18              
19             our $Dec_char = ".";
20             our $Neg_word = "negatif";
21             our $Dec_word = "koma";
22             our $Exp_word = "dikali sepuluh pangkat";
23             our $Zero_word = "nol";
24              
25             our %Digit_words = (
26             0 => $Zero_word,
27             1 => 'satu',
28             2 => 'dua',
29             3 => 'tiga',
30             4 => 'empat',
31             5 => 'lima',
32             6 => 'enam',
33             7 => 'tujuh',
34             8 => 'delapan',
35             9 => 'sembilan'
36             );
37              
38             our %Mult_words = (
39             0 => '',
40             1 => 'ribu',
41             2 => 'juta',
42             3 => 'milyar',
43             4 => 'triliun'
44             );
45              
46             # }}}
47              
48             ### public subs
49             # {{{ nums2words
50              
51             sub nums2words :Export {
52 15     15 1 9792 my @a = @_;
53 15         37 return join_it(n2w1(@a));
54 1     1   231 }
  1         3  
  1         3  
55              
56             # }}}
57             # {{{ nums2words_simple
58              
59             sub nums2words_simple :Export {
60 6     6 1 4016 my @a = @_;
61 6         15 return join_it(n2w5(@a));
62 1     1   223 }
  1         2  
  1         4  
63              
64             # }}}
65              
66             ### private subs
67              
68             # for debugging
69             our $DEBUG = 0;
70 13 50   13 1 21 sub hmm___ { my @a = @_;print "(", (caller 1)[3], ") Hmm, ", @a if $DEBUG; return; }
  13         27  
  13         16  
71             # {{{ n2w1 handle scientific notation
72             sub n2w1 {
73 15   100 15 1 42 my $num = shift // return '';
74              
75 14 100       32 return $Zero_word if $num >= 10 ** 15; # not quadrillion and more
76              
77 13         14 my @words;
78              
79 13 50 33     80 $num =~ /^(.+)[Ee](.+)$/ and
80             @words = (n2w2($1), $Exp_word, n2w2($2)) or
81             @words = n2w2($num);
82              
83 13         49 return @words;
84             }
85              
86             # }}}
87             # {{{ n2w2 handle negative sign and decimal
88              
89             sub n2w2 {
90 13   50 13 1 33 my $num = shift // return '';
91 13         14 my $is_neg;
92 13         16 my @words = ();
93              
94             # negative
95 13 100       28 $num < 0 and $is_neg++;
96 13         189 $num =~ s/^[\s\t]*[+-]*(.*)/$1/;
97              
98             # decimal
99 13 50 50     183 $num =~ /^(.+)\Q$Dec_char\E(.+)$/o and
      33        
      33        
      33        
100             @words = (n2w3($1), $Dec_word, n2w5($2)) or
101              
102             $num =~ /^\Q$Dec_char\E(.+)$/o and
103             @words = ($Digit_words{0}, $Dec_word, n2w5($1)) or
104              
105             $num =~ /^(.+)(?:\Q$Dec_char\E)?$/o and
106             @words = n2w3($1);
107              
108 13 100       33 $is_neg and
109             unshift @words, $Neg_word;
110              
111 13         64 return @words;
112             }
113              
114              
115             # }}}
116             # {{{ n2w3 handle digits before decimal
117              
118             sub n2w3 {
119 13   50 13 1 55 my $num = shift // return '';
120 13         19 my @words = ();
121 13         14 my $order = 0;
122 13         12 my $t;
123              
124 13         54 while($num =~ /^(.*?)([\d\D*]{1,3})$/) {
125 25         50 $num = $1;
126 25         50 ($t = $2) =~ s/\D//g;
127 25   100     176 $t = $t || 0;
128 25 100       88 unshift @words, $Mult_words{$order} if $t > 0;
129 25         49 unshift @words, n2w4($t, $order);
130 25         96 $order++;
131             }
132              
133 13 100       195 @words = ($Zero_word) if not join('',@words)=~/\S/;
134 13         56 hmm___ "for the left part of decimal i get: @words\n";
135 13         60 return @words;
136             }
137              
138             # }}}
139             # {{{ n2w4 handle clusters of thousands
140              
141             sub n2w4 {
142 25   50 25 1 63 my $num = shift // return '';
143 25         26 my $order = shift;
144 25         31 my @words = ();
145              
146 25         34 my $n1 = $num % 10;
147 25         44 my $n2 = ($num % 100 - $n1) / 10;
148 25         130 my $n3 = ($num - $n2*10 - $n1) / 100;
149              
150 25 100 100     144 ($n3 == 0 && $n2 == 0 && $n1 > 0) && (((
      66        
      100        
      100        
      100        
151             $n1 == 1 && $order == 1) && (@words = ("se"))) ||
152             (@words = ($Digit_words{$n1}) ));
153              
154 25 100 100     202 $n3 == 1 and @words = ("seratus") or
      66        
155             $n3 > 1 and @words = ($Digit_words{$n3}, "ratus");
156              
157 25 100 33     55 $n2 == 1 and (
      0        
      33        
      0        
158             $n1 == 0 and push(@words, "sepuluh") or
159             $n1 == 1 and push(@words, "sebelas") or
160             push(@words, $Digit_words{$n1}, "belas")
161             );
162              
163 25 100       49 $n2 > 1 and do {
164 7         14 push @words, $Digit_words{$n2}, "puluh";
165 7 100       69 push @words, $Digit_words{$n1} if $n1 > 0;
166             };
167              
168 25 50 100     89 ($n3 > 0 && $n2 == 0 && $n1 > 0) &&
      66        
169             push @words, $Digit_words{$n1} ;
170              
171 25 100 100     180 ($n3 != 0 || $n2 != 0 || $n1 != 0) &&
      100        
172             return @words;
173             }
174              
175             # }}}
176             # {{{ n2w5 handle digits after decimal
177             sub n2w5 {
178 6   100 6 1 17 my $num = shift // return '';
179              
180 5 100       15 return $Zero_word if $num >= 10 ** 15; # not quadrillion and more
181              
182 4         5 my @words = ();
183 4         6 my $i;
184             my $t;
185              
186 4         16 for( $i=0 ; $i<=length($num)-1 ; $i++ ) {
187 22         23 $t = substr($num, $i, 1);
188 22 50       81 exists $Digit_words{$t} and
189             push @words, $Digit_words{$t};
190             }
191              
192 4 50       21 @words = ($Zero_word) if not join('',@words)=~/\S/;
193 4         16 return @words;
194             }
195              
196             # }}}
197             # {{{ join_it join array of words, also join (se, ratus) -> seratus, etc.
198             sub join_it {
199 21     21 1 39 my @a = @_;
200 21         25 my $words = '';
201 21         18 my $w;
202              
203 21         44 while(defined( $w = shift @a)) {
204 95         96 $words .= $w;
205 95 100 100     527 $words .= ' ' unless not length $w or $w eq 'se' or not @a;
      100        
206             }
207 21         62 return $words;
208             }
209              
210             # }}}
211              
212             1;
213             __END__