File Coverage

blib/lib/Lingua/FRA/Word2Num.pm
Criterion Covered Total %
statement 23 30 76.6
branch 0 6 0.0
condition 2 4 50.0
subroutine 9 10 90.0
pod 3 3 100.0
total 37 53 69.8


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; eval: (folding-mode 1); coding:utf-8; -*-
2              
3             package Lingua::FRA::Word2Num;
4             # ABSTRACT: Word to number conversion in French
5              
6 1     1   137486 use 5.16.0;
  1         4  
7 1     1   6 use utf8;
  1         2  
  1         15  
8 1     1   35 use warnings;
  1         2  
  1         87  
9              
10             # {{{ use block
11              
12 1     1   745 use Export::Attrs;
  1         14261  
  1         36  
13 1     1   1411 use Parse::RecDescent;
  1         57320  
  1         10  
14              
15             # }}}
16             # {{{ var block
17             our $VERSION = '0.2603300';
18             my $parser = fra_numerals();
19              
20             # }}}
21              
22             # {{{ w2n convert text to number
23              
24             sub w2n :Export {
25 4   100 4 1 323436 my $input = shift // return;
26              
27 3         43 return $parser->numeral($input);
28 1     1   162 }
  1         3  
  1         14  
29              
30             # }}}
31             # {{{ fra_numerals create parser for numerals
32              
33             sub fra_numerals {
34 1     1 1 6 return Parse::RecDescent->new(q{
35            
36              
37             numeral: mega
38             | kOhOd
39             | 'zéro' { 0 }
40             | { }
41              
42             number: 'un' { 1 }
43             | 'deux' { 2 }
44             | 'trois' { 3 }
45             | 'quatre' { 4 }
46             | 'cinq' { 5 }
47             | 'six' { 6 }
48             | 'sept' { 7 }
49             | 'huit' { 8 }
50             | 'neuf' { 9 }
51             | 'dix-sept' { 17 }
52             | 'dix-huit' { 18 }
53             | 'dix-neuf' { 19 }
54             | 'dix' { 10 }
55             | 'onze' { 11 }
56             | 'douze' { 12 }
57             | 'treize' { 13 }
58             | 'quatorze' { 14 }
59             | 'quinze' { 15 }
60             | 'seize' { 16 }
61              
62             tens: 'vingt' { 20 }
63             | 'trente' { 30 }
64             | 'quarante' { 40 }
65             | 'cinquante' { 50 }
66             | 'soixante-dix' { 70 }
67             | 'soixante' { 60 }
68             | /quatre-vingts?/ { 80 }
69              
70             deca: tens /-?/ number { $item[1] + $item[3] }
71             | tens 'et' number { $item[1] + $item[3] }
72             | tens
73             | number
74              
75             hecto: number /cents?/ deca { $item[1] * 100 + $item[3] }
76             | number /cents?/ { $item[1] * 100 }
77             | /cents?/ deca { 100 + $item[2] }
78             | 'cent' { 100 }
79              
80             hOd: hecto
81             | deca
82              
83             kilo: hOd /milles?/ hOd { $item[1] * 1000 + $item[3] }
84             | hOd /milles?/ { $item[1] * 1000 }
85             | /milles?/ hOd { 1000 + $item[2] }
86             | 'mille' { 1000 }
87              
88             kOhOd: kilo
89             | hOd
90              
91             mega: kOhOd /millions?/ kOhOd { $item[1] * 1_000_000 + $item[3] }
92             });
93             }
94             # }}}
95             # {{{ ordinal2cardinal convert ordinal text to cardinal text
96              
97             sub ordinal2cardinal :Export {
98 0   0 0 1   my $input = shift // return;
99              
100             # French ordinals:
101             # "premier" / "première" → "un" (fully suppletive for 1st)
102             # All others: cardinal stem + "ième"
103             # Reverse stem changes: cinqu→cinq, neuv→neuf
104              
105 0 0         return 'un' if $input =~ m{\A premi(?:er|ère) \z}xms;
106              
107             # Must end with "ième" to be an ordinal
108 0 0         $input =~ s{ième\z}{}xms or return;
109              
110             # Reverse stem changes
111 0           $input =~ s{cinqu\z}{cinq}xms;
112 0           $input =~ s{neuv\z}{neuf}xms;
113              
114             # French drops final -e before -ième (quatre→quatrième, onze→onzième).
115             # Restore it unless the stem already ends in a vowel.
116 0 0         $input .= 'e' if $input =~ m{[^aeiouyâêîôûéèëïü]\z}xms;
117              
118 0           return $input;
119 1     1   684 }
  1         3  
  1         6  
120              
121             # }}}
122              
123             1;
124              
125             __END__