| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Lingua::pt_BR::Nums2Words; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 63474 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 24 |  | 
| 4 | 1 |  |  | 1 |  | 4 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 21 |  | 
| 5 | 1 |  |  | 1 |  | 4 | use Exporter 'import'; | 
|  | 1 |  |  |  |  | 9 |  | 
|  | 1 |  |  |  |  | 31 |  | 
| 6 | 1 |  |  | 1 |  | 5 | use Carp; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 58 |  | 
| 7 | 1 |  |  | 1 |  | 5 | use utf8; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 3 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | our $VERSION = '0.02'; | 
| 10 |  |  |  |  |  |  | our @EXPORT_OK = qw/num2word/; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | =encoding utf8 | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | =head1 NAME | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | Lingua::pt_BR::Nums2Words - Takes a number and gives back its written | 
| 17 |  |  |  |  |  |  | form in Brazilian Portuguese | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | use Lingua::pt_BR::Nums2Words ('num2word'); | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | print num2word(91)        # prints 'noventa e um' | 
| 24 |  |  |  |  |  |  | print num2word('19')      # prints 'dezenove' | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | print num2word(1000)      # prints 'mil' | 
| 27 |  |  |  |  |  |  | print num2word(1001)      # prints 'mil e um' | 
| 28 |  |  |  |  |  |  | print num2word(1_001_001) # prints 'um milhão, mil e um' | 
| 29 |  |  |  |  |  |  | print num2word(1_001_250) # prints 'um milhão, mil duzentos e cinquenta' | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | Takes a number and gives back its written form in Brazilian | 
| 34 |  |  |  |  |  |  | Portuguese. | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | B: 1000 will produce 'mil', and not 'um mil'. | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | =head1 METHODS | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | =cut | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | my %cardinals; | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | $cardinals{units}      = [undef, qw/um dois três quatro cinco seis sete oito | 
| 45 |  |  |  |  |  |  | nove/]; | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | $cardinals{first_tens} = [undef, qw/onze doze treze quatorze quinze dezesseis | 
| 48 |  |  |  |  |  |  | dezessete dezoito dezenove/]; | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | $cardinals{tens}       = [undef, qw/dez vinte trinta quarenta cinquenta sessenta | 
| 51 |  |  |  |  |  |  | setenta oitenta noventa/]; | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | $cardinals{hundreds}   = [undef, qw/cento duzentos trezentos quatrocentos | 
| 54 |  |  |  |  |  |  | quinhentos seiscentos setecentos oitocentos novecentos/]; | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | $cardinals{megas}      = [undef, qw/mil milh bilh trilh quadrilh quintilh/]; | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | =head2 num2word( $number ) | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | Receives a number and returns it written in words. | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | my $written_number = nums2words(991); | 
| 63 |  |  |  |  |  |  | print $written_number        # prints 'novecentos e noventa e um' | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | =cut | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | sub num2word { | 
| 68 | 38 |  |  | 38 | 1 | 2662 | my $number = shift; | 
| 69 | 38 | 100 |  |  |  | 205 | croak 'No argument provided' unless defined $number; | 
| 70 | 37 | 100 |  |  |  | 493 | croak "Not a workable number: $number" unless $number =~ /^\d{1,19}$/x; | 
| 71 | 33 | 100 |  |  |  | 69 | if ($number ==   0) { return 'zero' } | 
|  | 2 |  |  |  |  | 8 |  | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 31 |  |  |  |  | 53 | return _solve_triads( _make_triads($number) ); | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | =head1 INTERNALS | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | These methods should not be used directly (unless you know what you're | 
| 79 |  |  |  |  |  |  | doing).  They are documented here just for the sake of completeness. | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | =head2 _make_triads( $number ) | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | Receives a number, splits it in triads (according to the following | 
| 84 |  |  |  |  |  |  | examples) and returns a list of triads. Examples: 123 turns to the | 
| 85 |  |  |  |  |  |  | list (123). 12345 turns to the list (12, 345). 1234567 turns to the | 
| 86 |  |  |  |  |  |  | list (1, 234, 567). | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | =cut | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | sub _make_triads { | 
| 91 | 31 |  |  | 31 |  | 42 | my $number = shift; | 
| 92 | 31 |  |  |  |  | 37 | my @triads; | 
| 93 | 31 |  | 100 |  |  | 75 | my $offset = (length $number) % 3 || 3; | 
| 94 |  |  |  |  |  |  |  | 
| 95 | 31 |  |  |  |  | 86 | while (my $triad = substr $number, 0, $offset, '') { | 
| 96 | 81 |  |  |  |  | 103 | push @triads, $triad; | 
| 97 | 81 | 100 |  |  |  | 159 | if ($offset != 3) { $offset = 3 } | 
|  | 24 |  |  |  |  | 50 |  | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 | 31 |  |  |  |  | 87 | return @triads; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | =head2 _solve_triads( @triads ) | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | Receives a list of triads, calls the function _solve_triad in each of | 
| 106 |  |  |  |  |  |  | them and apply the "megas" (millions, billions, trillions). | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | =cut | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | sub _solve_triads { | 
| 111 | 31 |  |  | 31 |  | 67 | my @triads = @_; | 
| 112 | 31 |  |  |  |  | 40 | my $megas_counter = $#triads; | 
| 113 | 31 |  |  |  |  | 39 | my @triads_str; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 31 |  |  |  |  | 49 | for my $triad (@triads) { | 
| 116 | 81 | 100 |  |  |  | 152 | if ($triad == 0) { | 
| 117 | 15 |  |  |  |  | 17 | $megas_counter--; | 
| 118 | 15 |  |  |  |  | 21 | next; | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 | 66 |  |  |  |  | 93 | my $triad_str = _solve_triad($triad); | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 66 | 100 |  |  |  | 104 | if ($megas_counter > 0) { | 
| 124 | 36 |  |  |  |  | 47 | my $mega = $cardinals{megas}->[$megas_counter]; | 
| 125 | 36 | 100 |  |  |  | 55 | if ($megas_counter > 1) { $mega .= $triad == 1 ? 'ão' : 'ões' } | 
|  | 20 | 100 |  |  |  | 34 |  | 
| 126 | 36 |  |  |  |  | 60 | $triad_str .= " $mega"; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 36 | 100 |  |  |  | 59 | if ($triad_str eq 'um mil') { $triad_str = 'mil' } | 
|  | 6 |  |  |  |  | 10 |  | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 36 |  |  |  |  | 42 | $megas_counter--; | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 66 |  |  |  |  | 98 | push @triads_str, $triad_str; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  |  | 
| 136 | 31 |  |  |  |  | 34 | my $resp_str; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 31 | 100 |  |  |  | 63 | if (@triads_str == 1) { | 
| 139 | 10 |  |  |  |  | 13 | $resp_str = $triads_str[0]; | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  | else { | 
| 142 | 21 |  |  |  |  | 57 | $resp_str .= join ', ', @triads_str[0 .. $#triads_str - 1]; | 
| 143 |  |  |  |  |  |  |  | 
| 144 | 21 |  |  |  |  | 34 | my $last_triad = $triads[-1]; | 
| 145 | 21 |  |  |  |  | 24 | my $last_triad_str; | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 21 | 100 | 100 |  |  | 60 | if ($last_triad % 100 == 0 || $last_triad < 100) { | 
| 148 | 13 |  |  |  |  | 18 | $last_triad_str = "e $triads_str[-1]"; | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  | else { | 
| 151 | 8 |  |  |  |  | 11 | $last_triad_str = $triads_str[-1]; | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 21 |  |  |  |  | 38 | $resp_str .= " $last_triad_str"; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  |  | 
| 157 | 31 |  |  |  |  | 148 | return $resp_str; | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | =head2 _solve_triad( $number ) | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | Receives a number with one to three digits (a triad) and returns it | 
| 163 |  |  |  |  |  |  | written in words. | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | =cut | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | sub _solve_triad { | 
| 168 | 66 |  |  | 66 |  | 86 | my $number = shift; | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 66 | 100 |  |  |  | 104 | if ($number == 100) { return 'cem' } | 
|  | 1 |  |  |  |  | 2 |  | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 65 |  |  |  |  | 149 | my $padded_number = sprintf "%03d", $number; | 
| 173 | 65 |  |  |  |  | 154 | my ($hundreds, $tens, $units) = split '', $padded_number; | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 65 |  |  |  |  | 89 | my @resp; | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 65 | 100 |  |  |  | 89 | if ($hundreds) { push @resp, $cardinals{hundreds}->[$hundreds] } | 
|  | 21 |  |  |  |  | 37 |  | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 65 |  |  |  |  | 94 | my $first_tens = $tens . $units; | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 65 | 100 | 100 |  |  | 141 | if ($first_tens > 10 and $first_tens < 20) { | 
| 182 | 2 |  |  |  |  | 5 | push @resp, $cardinals{first_tens}->[$units]; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  | else { | 
| 185 | 63 | 100 |  |  |  | 90 | if ($tens)  { push @resp, $cardinals{tens}->[$tens]   } | 
|  | 8 |  |  |  |  | 14 |  | 
| 186 | 63 | 100 |  |  |  | 86 | if ($units) { push @resp, $cardinals{units}->[$units] } | 
|  | 48 |  |  |  |  | 79 |  | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 | 65 |  |  |  |  | 159 | return join ' e ', @resp; | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | 1; | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | Lingua::PT::Nums2Words for pt_PT Portuguese. | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | =head1 AUTHOR | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | Gil Magno Egils@cpan.orgE | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | =head1 THANKS TO | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | Italo Gonçales (cpan:GONCALES) Eitalo.goncales@gmail.comE | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | Copyright (C) 2015 by Gil Magno | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | This library is free software; you can redistribute it and/or modify | 
| 211 |  |  |  |  |  |  | it under the same terms as Perl itself, either Perl version 5.20.1 or, | 
| 212 |  |  |  |  |  |  | at your option, any later version of Perl 5 you may have available. | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | =cut |