File Coverage

blib/lib/Lingua/OCI/Word2Num.pm
Criterion Covered Total %
statement 26 43 60.4
branch 0 16 0.0
condition 2 4 50.0
subroutine 9 11 81.8
pod 3 3 100.0
total 40 77 51.9


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; eval: (folding-mode 1); coding:utf-8; -*-
2              
3             package Lingua::OCI::Word2Num;
4             # ABSTRACT: Word to number conversion in Occitan
5              
6 1     1   143554 use 5.16.0;
  1         4  
7 1     1   4 use utf8;
  1         3  
  1         12  
8 1     1   25 use warnings;
  1         1  
  1         69  
9              
10             # {{{ use block
11              
12 1     1   1331 use Parse::RecDescent;
  1         47921  
  1         7  
13 1     1   732 use Export::Attrs;
  1         13064  
  1         8  
14              
15             # }}}
16             # {{{ var block
17             our $VERSION = '0.2603300';
18             my $parser = oci_numerals();
19              
20             # }}}
21              
22             # {{{ w2n convert text to number
23              
24             sub w2n :Export {
25 36   100 36 1 1510618 my $input = shift // return;
26              
27 35         163 $input = lc $input;
28 35         217 $input =~ s/\s+/ /g;
29 35         265 $input =~ s/^\s+|\s+$//g;
30              
31 35         446 return $parser->numeral($input);
32 1     1   168 }
  1         2  
  1         8  
33             # }}}
34             # {{{ oci_numerals create parser for numerals
35              
36             sub oci_numerals {
37 1     1 1 11 return Parse::RecDescent->new(q{
38            
39            
40              
41             numeral: mega
42             | kOhOd
43             | /z(?:e|è)ro/ { 0 }
44             | { }
45              
46             number: 'un' { 1 }
47             | 'dos' { 2 }
48             | 'tres' { 3 }
49             | 'quatre' { 4 }
50             | 'cinc' { 5 }
51             | /si(?:e|è)is/ { 6 }
52             | /u(?:e|è)ch/ { 8 }
53             | /n(?:o|ò)u/ { 9 }
54             | /d(?:e|è)tz-e-s(?:e|è)t/ { 17 }
55             | /d(?:e|è)tz-e-u(?:e|è)ch/ { 18 }
56             | /d(?:e|è)tz-e-n(?:o|ò)u/ { 19 }
57             | /d(?:e|è)tz/ { 10 }
58             | 'onze' { 11 }
59             | 'dotze' { 12 }
60             | 'tretze' { 13 }
61             | /cat(?:o|ò)rze/ { 14 }
62             | 'quinze' { 15 }
63             | 'setze' { 16 }
64             | /s(?:e|è)t/ { 7 }
65             | 'vint-e-un' { 21 }
66             | 'vint-e-dos' { 22 }
67             | 'vint-e-tres' { 23 }
68             | 'vint-e-quatre' { 24 }
69             | 'vint-e-cinc' { 25 }
70             | /vint-e-si(?:e|è)is/ { 26 }
71             | /vint-e-s(?:e|è)t/ { 27 }
72             | /vint-e-u(?:e|è)ch/ { 28 }
73             | /vint-e-n(?:o|ò)u/ { 29 }
74             | 'vint' { 20 }
75              
76             tens: 'trenta' { 30 }
77             | 'quaranta' { 40 }
78             | 'cinquanta' { 50 }
79             | 'seissanta' { 60 }
80             | 'setanta' { 70 }
81             | 'ochanta' { 80 }
82             | 'nonanta' { 90 }
83              
84             hundreds: number /\-?\s?cents?/ { $item[1] * 100 }
85             | /cents?/ { 100 }
86              
87             deca: tens /-e-/ number { $item[1] + $item[3] }
88             | tens
89             | number
90              
91             hecto: hundreds deca { $item[1] + $item[2] }
92             | hundreds
93              
94             hOd: hecto
95             | deca
96              
97             kilo: hOd milnotmeg hOd { $item[1] * 1000 + $item[3] }
98             | hOd milnotmeg { $item[1] * 1000 }
99             | milnotmeg hOd { 1000 + $item[2] }
100             | milnotmeg { 1000 }
101              
102             milnotmeg: ...!'milion' 'mila'
103              
104             kOhOd: kilo
105             | hOd
106              
107             mega: hOd /milions?/ kOhOd { $item[1] * 1_000_000 + $item[3] }
108             | hOd /milions?/ { $item[1] * 1_000_000 }
109             });
110             }
111              
112             # }}}
113             # {{{ ordinal2cardinal convert ordinal text to cardinal text
114              
115             sub ordinal2cardinal :Export {
116 0   0 0 1   my $input = shift // return;
117              
118             # Occitan ordinals 1-10 are fully irregular
119 0           state $irregular = {
120             'primièr' => 'un', 'primièra' => 'un',
121             'segond' => 'dos', 'segonda' => 'dos',
122             'tresen' => 'tres', 'tresena' => 'tres',
123             'quatren' => 'quatre', 'quatrena' => 'quatre',
124             'cinquen' => 'cinc', 'cinquena' => 'cinc',
125             'sièisen' => 'sièis', 'sièisena' => 'sièis',
126             'seten' => 'sèt', 'setena' => 'sèt',
127             'uèchen' => 'uèch', 'uèchena' => 'uèch',
128             'nòven' => 'nòu', 'nòvena' => 'nòu',
129             'desen' => 'dètz', 'desena' => 'dètz',
130             };
131              
132 0 0         return $irregular->{$input} if exists $irregular->{$input};
133              
134             # Regular (11+): cardinal stem + "en" (masc) or "ena" (fem)
135             # Try feminine first (longer suffix)
136 0 0         if ($input =~ s{ena\z}{}xms) {
137 0           _oci_restore_vowel(\$input);
138 0           return $input;
139             }
140              
141             # Masculine: strip "en"
142 0 0         $input =~ s{en\z}{}xms or return;
143              
144 0           _oci_restore_vowel(\$input);
145              
146 0           return $input;
147 1     1   709 }
  1         5  
  1         4  
148              
149             # }}}
150             # {{{ _oci_restore_vowel restore dropped vowel on stem
151              
152             sub _oci_restore_vowel {
153 0     0     my $ref = shift;
154              
155             # Occitan drops the final vowel before ordinal suffixes. The dropped
156             # vowel varies by word, so we restore it based on the stem ending.
157              
158             # nòu family: dètz-e-nò→dètz-e-nòu (stem ends in "ò" vowel → need "u")
159 0 0         if ($$ref =~ m{n[oò]\z}xms) { $$ref .= 'u' }
  0 0          
    0          
    0          
    0          
160             # quatre: vint-e-quatr→vint-e-quatre
161 0           elsif ($$ref =~ m{tr\z}xms) { $$ref .= 'e' }
162             # decades (trenta, quaranta, etc.): trent→trenta, quarant→quaranta
163 0           elsif ($$ref =~ m{[ae]nt\z}xms) { $$ref .= 'a' }
164             # mila: mil→mila (Occitan "mila" for 1000)
165 0           elsif ($$ref =~ m{mil\z}xms) { $$ref .= 'a' }
166             # teens ending in -z: onz→onze, dotz→dotze, tretz→tretze, etc.
167 0           elsif ($$ref =~ m{z\z}xms) { $$ref .= 'e' }
168              
169 0           return;
170             }
171              
172             # }}}
173              
174             1;
175              
176             __END__