File Coverage

blib/lib/Lingua/POR/Words2Nums.pm
Criterion Covered Total %
statement 42 65 64.6
branch 7 30 23.3
condition 5 7 71.4
subroutine 8 9 88.8
pod 2 2 100.0
total 64 113 56.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::POR::Words2Nums;
4             # ABSTRACT: Converts Portuguese words to numbers
5              
6 1     1   83103 use 5.16.0;
  1         3  
7 1     1   4 use utf8;
  1         1  
  1         9  
8 1     1   31 use warnings;
  1         1  
  1         43  
9              
10             # {{{ use block
11              
12 1     1   447 use Export::Attrs;
  1         7830  
  1         18  
13              
14             # }}}
15             # {{{ var block
16             our $VERSION = '0.2603300';
17              
18             my (%values,@values,%bigvalues,@bigvalues);
19              
20             BEGIN {
21 1     1   203 %values = (
22             mil => 1000,
23              
24             novecentos => 900,
25             oitocentos => 800,
26             setecentos => 700,
27             seiscentos => 600,
28             quinhentos => 500,
29             quatrocentos => 400,
30             trezentos => 300,
31             duzentos => 200,
32             cem => 100,
33              
34             cento => 100,
35              
36             noventa => 90,
37             oitenta => 80,
38             setenta => 70,
39             sessenta => 60,
40             cinquenta => 50,
41             quarenta => 40,
42             trinta => 30,
43             vinte => 20,
44              
45             dezanove => 19,
46             dezoito => 18,
47             dezassete => 17,
48             dezasseis => 16,
49             quinze => 15,
50             catorze => 14,
51             treze => 13,
52             doze => 12,
53             onze => 11,
54             dez => 10,
55              
56             nove => 9,
57             oito => 8,
58             sete => 7,
59             seis => 6,
60             cinco => 5,
61             quatro => 4,
62             'três' => 3,
63             dois => 2,
64             um => 1,
65             zero => 0,
66             );
67              
68 1         8 @values = sort {$values{$b} <=> $values{$a}} keys %values;
  162         195  
69              
70 1         5 %bigvalues = (
71             bili => 1000000000000,
72             milh => 1000000,
73             );
74              
75 1         4 @bigvalues = sort {$bigvalues{$b} <=> $bigvalues{$a}} keys %bigvalues;
  1         308  
76              
77             }
78              
79             # }}}
80              
81             # {{{ word2num
82              
83             sub word2num :Export {
84 5   100 5 1 126289 $_ = shift // return;
85 4         6 my $task = $_;
86 4         5 my $result = 0;
87              
88 4         8 for my $val (@bigvalues) {
89 8         12 my $expr = "${val}ões|${val}ão";
90 8 50       217 if (s/(.+)mil(?=.*(?:$expr))//) {
91 0         0 my $big = $1;
92 0         0 for my $value (@values) {
93 0         0 $big =~ s/$value/
94 0         0 $result += ($values{$value} * $bigvalues{$val} * 1000)/e;
95             }
96             }
97 8 50       146 if (s/(.+)(?:$expr)//) {
98 0         0 my $sma = $1;
99 0         0 for my $value (@values) {
100 0         0 $sma =~ s/$value/
101 0         0 $result += ($values{$value} * $bigvalues{$val})/e;
102             }
103             }
104             }
105              
106 4 100       15 if (s/(.+?)mil//) {
107 2         5 my $thousands = $1;
108 2 50       8 if ($thousands =~ /^\s*e?\s*$/) {
109 0         0 $result += 1000;
110             }
111             else {
112 2         3 for my $value (@values) {
113 78         309 $thousands =~ s/$value/$result += ($values{$value} * 1000)/e;
  2         17  
114             }
115             }
116             }
117              
118 4         6 for my $value (@values) {
119 156         606 s/$value/$result += $values{$value}/e;
  6         18  
120             }
121              
122 4 100 100     18 if ($result == 0 && $task !~ m{\Azero\z}xms ) {
123 1         1 $result = undef;
124             }
125              
126 4         7 return $result;
127 1     1   7 }
  1         1  
  1         4  
128              
129             # }}}
130             # {{{ ordinal2cardinal convert ordinal text to cardinal text
131              
132             sub ordinal2cardinal :Export {
133 0   0 0 1   my $input = shift // return;
134              
135             # Portuguese ordinals 1-10 are fully irregular
136 0           state $irregular = {
137             'primeiro' => 'um', 'primeira' => 'um',
138             'segundo' => 'dois', 'segunda' => 'dois',
139             'terceiro' => 'três', 'terceira' => 'três',
140             'quarto' => 'quatro', 'quarta' => 'quatro',
141             'quinto' => 'cinco', 'quinta' => 'cinco',
142             'sexto' => 'seis', 'sexta' => 'seis',
143             'sétimo' => 'sete', 'sétima' => 'sete',
144             'oitavo' => 'oito', 'oitava' => 'oito',
145             'nono' => 'nove', 'nona' => 'nove',
146             'décimo' => 'dez', 'décima' => 'dez',
147             };
148              
149 0 0         return $irregular->{$input} if exists $irregular->{$input};
150              
151             # Regular (11+): cardinal (drop final vowel) + "ésimo/ésima"
152 0 0         $input =~ s{ésim[oa]\z}{}xms or return;
153              
154             # Portuguese drops the final vowel before adding -ésimo. The dropped
155             # vowel varies by word, so we restore it based on the stem ending.
156              
157             # stems ending in -z: onz→onze, doz→doze, trez→treze, catorz→catorze, quinz→quinze
158 0 0         if ($input =~ m{z\z}xms) { $input .= 'e' }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
159             # oito family: dezoit→dezoito, oit→oito
160 0           elsif ($input =~ m{oit\z}xms) { $input .= 'o' }
161             # sete family: dezasset→dezassete, set→sete
162 0           elsif ($input =~ m{set\z}xms) { $input .= 'e' }
163             # vinte: vint→vinte
164 0           elsif ($input =~ m{vint\z}xms) { $input .= 'e' }
165             # decades (trinta, quarenta, etc.): trint→trinta, quarent→quarenta
166 0           elsif ($input =~ m{nt\z}xms) { $input .= 'a' }
167             # cinco: cinc→cinco
168 0           elsif ($input =~ m{c\z}xms) { $input .= 'o' }
169             # nove family: dezanov→dezanove, nov→nove
170 0           elsif ($input =~ m{ov\z}xms) { $input .= 'e' }
171             # quatro: quatr→quatro
172 0           elsif ($input =~ m{tr\z}xms) { $input .= 'o' }
173              
174 0           return $input;
175 1     1   443 }
  1         8  
  1         4  
176              
177             # }}}
178              
179             1;
180              
181             __END__