File Coverage

blib/lib/Lingua/HRV/Word2Num.pm
Criterion Covered Total %
statement 23 36 63.8
branch 0 6 0.0
condition 2 19 10.5
subroutine 9 10 90.0
pod 3 3 100.0
total 37 74 50.0


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; mode:folding; coding:utf-8; -*-
2              
3             package Lingua::HRV::Word2Num;
4             # ABSTRACT: Word to number conversion in Croatian
5              
6 1     1   111081 use 5.16.0;
  1         5  
7 1     1   7 use utf8;
  1         3  
  1         15  
8 1     1   36 use warnings;
  1         2  
  1         162  
9              
10             # {{{ use block
11              
12 1     1   759 use Export::Attrs;
  1         13882  
  1         8  
13 1     1   1549 use Parse::RecDescent;
  1         54891  
  1         11  
14              
15             # }}}
16             # {{{ var block
17             our $VERSION = '0.2603300';
18             my $parser = hrv_numerals();
19              
20             # }}}
21              
22             # {{{ w2n convert text to number
23              
24             sub w2n :Export {
25 2   100 2 1 238279 my $input = shift // return;
26              
27 1         13 return $parser->numeral($input);
28 1     1   155 }
  1         3  
  1         9  
29              
30             # }}}
31             # {{{ hrv_numerals create parser for numerals
32              
33             sub hrv_numerals {
34 1     1 1 6 return Parse::RecDescent->new(q{
35            
36              
37             numeral: mega
38             | kOhOd
39             | 'nula' { 0 }
40             | { }
41              
42             number: 'jedanaest' { 11 }
43             | 'dvanaest' { 12 }
44             | 'trinaest' { 13 }
45             | "četrnaest" { 14 }
46             | 'petnaest' { 15 }
47             | "šesnaest" { 16 }
48             | 'sedamnaest' { 17 }
49             | 'osamnaest' { 18 }
50             | 'devetnaest' { 19 }
51             | 'jedan' { 1 }
52             | 'jedna' { 1 }
53             | 'dvije' { 2 }
54             | 'dva' { 2 }
55             | 'tri' { 3 }
56             | "četiri" { 4 }
57             | 'pet' { 5 }
58             | "šest" { 6 }
59             | 'sedam' { 7 }
60             | 'osam' { 8 }
61             | 'devet' { 9 }
62             | 'deset' { 10 }
63              
64             tens: 'dvadeset' { 20 }
65             | 'trideset' { 30 }
66             | "četrdeset" { 40 }
67             | 'pedeset' { 50 }
68             | "šezdeset" { 60 }
69             | 'sedamdeset' { 70 }
70             | 'osamdeset' { 80 }
71             | 'devedeset' { 90 }
72              
73             deca: tens number { $item[1] + $item[2] }
74             | tens
75             | number
76              
77             hecto: number /sto/ deca { $item[1] * 100 + $item[3] }
78             | number /sto/ { $item[1] * 100 }
79             | 'dvjesto' deca { 200 + $item[2] }
80             | 'dvjesto' { 200 }
81             | 'tristo' deca { 300 + $item[2] }
82             | 'tristo' { 300 }
83             | "četiristo" deca { 400 + $item[2] }
84             | "četiristo" { 400 }
85             | 'petsto' deca { 500 + $item[2] }
86             | 'petsto' { 500 }
87             | "šeststo" deca { 600 + $item[2] }
88             | "šeststo" { 600 }
89             | 'sedamsto' deca { 700 + $item[2] }
90             | 'sedamsto' { 700 }
91             | 'osamsto' deca { 800 + $item[2] }
92             | 'osamsto' { 800 }
93             | 'devetsto' deca { 900 + $item[2] }
94             | 'devetsto' { 900 }
95             | 'sto' deca { 100 + $item[2] }
96             | 'sto' { 100 }
97              
98             hOd: hecto
99             | deca
100              
101             kilo: hOd /tisuć[ae]?/ hOd { $item[1] * 1000 + $item[3] }
102             | hOd /tisuć[ae]?/ { $item[1] * 1000 }
103             | number /tisuć[ae]?/ hOd { $item[1] * 1000 + $item[3] }
104             | number /tisuć[ae]?/ { $item[1] * 1000 }
105             | /tisuća/ hOd { 1000 + $item[2] }
106             | /tisuća/ { 1000 }
107              
108             kOhOd: kilo
109             | hOd
110              
111             mega: hOd megas kOhOd { $item[1] * 1_000_000 + $item[3] }
112             | hOd megas { $item[1] * 1_000_000 }
113             | 'jedan' 'milijun' kOhOd { 1_000_000 + $item[3] }
114             | 'jedan' 'milijun' { 1_000_000 }
115             | 'milijun' kOhOd { 1_000_000 + $item[2] }
116             | 'milijun' { 1_000_000 }
117              
118             megas: 'milijuna'
119             | 'milijun'
120             });
121             }
122              
123             # }}}
124             # {{{ ordinal2cardinal convert ordinal text to cardinal text
125              
126             sub ordinal2cardinal :Export {
127 0   0 0 1   my $input = shift // return;
128              
129             # Croatian ordinals: strip gender/case suffixes, then map stems.
130             # Inflection: -i/-a/-o/-og(a)/-om(u)/-im (masc/fem/neut/oblique).
131              
132 0           my %irregular = (
133             'nulti' => 'nula',
134             'prvi' => 'jedan',
135             'drugi' => 'dva',
136             'treći' => 'tri',
137             'četvrti' => 'četiri',
138             'peti' => 'pet',
139             'šesti' => 'šest',
140             'sedmi' => 'sedam',
141             'osmi' => 'osam',
142             'deveti' => 'devet',
143             'deseti' => 'deset',
144             'jedanaesti' => 'jedanaest',
145             'dvanaesti' => 'dvanaest',
146             'trinaesti' => 'trinaest',
147             'četrnaesti' => 'četrnaest',
148             'petnaesti' => 'petnaest',
149             'šesnaesti' => 'šesnaest',
150             'sedamnaesti' => 'sedamnaest',
151             'osamnaesti' => 'osamnaest',
152             'devetnaesti' => 'devetnaest',
153             'dvadeseti' => 'dvadeset',
154             'trideseti' => 'trideset',
155             'četrdeseti' => 'četrdeset',
156             'pedeseti' => 'pedeset',
157             'šezdeseti' => 'šezdeset',
158             'sedamdeseti' => 'sedamdeset',
159             'osamdeseti' => 'osamdeset',
160             'devedeseti' => 'devedeset',
161             'dvjestoti' => 'dvjesto',
162             'tristoti' => 'tristo',
163             'četiristoti' => 'četiristo',
164             'petstoti' => 'petsto',
165             'šeststoti' => 'šeststo',
166             'sedamstoti' => 'sedamsto',
167             'osamstoti' => 'osamsto',
168             'devetstoti' => 'devetsto',
169             'stoti' => 'sto',
170             'tisućiti' => 'tisuća',
171             'milijunti' => 'milijun',
172             );
173              
174             # Compound ordinals: ALL components are ordinal forms.
175             # Normalize each word individually, then look up in the mapping.
176 0           my @words = split /\s+/, $input;
177 0           my @result;
178 0           my $matched = 0;
179              
180 0           for my $word (@words) {
181             # Strip gender/case suffixes to masculine nominative (-i)
182 0           my $norm = $word;
183 0 0 0       $norm =~ s{oga\z}{i}xms
      0        
      0        
      0        
      0        
184             or $norm =~ s{og\z}{i}xms
185             or $norm =~ s{omu\z}{i}xms
186             or $norm =~ s{om\z}{i}xms
187             or $norm =~ s{im\z}{i}xms
188             or $norm =~ s{a\z}{i}xms # fem: prva → prvi
189             or $norm =~ s{o\z}{i}xms; # neut: prvo → prvi
190              
191 0 0         if (exists $irregular{$norm}) {
192 0           push @result, $irregular{$norm};
193 0           $matched = 1;
194             }
195             else {
196 0           push @result, $word; # pass through unchanged (connectors, etc.)
197             }
198             }
199              
200 0 0         return $matched ? join(' ', @result) : undef;
201 1     1   951 }
  1         2  
  1         7  
202              
203             # }}}
204              
205             1;
206              
207             __END__