File Coverage

blib/lib/Lingua/RU/Numeral.pm
Criterion Covered Total %
statement 273 273 100.0
branch 220 220 100.0
condition 74 76 97.3
subroutine 16 16 100.0
pod 3 3 100.0
total 586 588 99.6


line stmt bran cond sub pod time code
1             package Lingua::RU::Numeral;
2              
3 1     1   70179 use 5.010;
  1         12  
4 1     1   4 use strict;
  1         2  
  1         15  
5 1     1   4 use warnings;
  1         1  
  1         38  
6 1     1   6 use utf8;
  1         2  
  1         4  
7 1     1   32 use open qw(:std :utf8);
  1         2  
  1         6  
8              
9             require Exporter;
10              
11             our @ISA = qw(Exporter);
12              
13             our %EXPORT_TAGS = ( 'all' => [ qw(
14             num2cardinal
15             case_endings
16             spelled_out_number
17             ) ] );
18              
19             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
20              
21             our @EXPORT = qw( );
22              
23             our $VERSION = '0.07';
24              
25              
26             ########################
27             # num2cardinal INPUT #
28             ########################
29             # SCALAR:
30             #~~~~~~~~
31             # 0. $number -- число для обработки, e.g: 1234567890
32              
33             #~~~~~~~~~~~
34             # HASH keys:
35             #~~~~~~~~~~~
36             # 1. 'case' key -- падеж: числительное: Количественное | Порядковое
37             # (default) n = nominative - Именительный: есть кто? что? | какой?
38             # g = genitive - Родительный: нет кого? чего? | какого?
39             # d = dative - Дательный: рад кому? чему? | какому?
40             # a = accusative - Винительный: вижу кого? что? | какой?
41             # i = instrumental - Творительный: оплачу кем? чем? | каким?
42             # p = prepositional - Предложный: думаю о ком? о чём?| о каком?
43              
44             # 2. 'gender' key -- род:
45             # (default) m = masculine (Мужской)
46             # f = feminine (Женский)
47             # n = neuter (Средний)
48              
49             # 3. 'multi' key -- единственное(undef|0|'singular') или множественное число (>0|'plural'). By default, 'singular'
50             # 4. 'object' key -- inanimate(неодушевлённый) или animate(одушевлённый) предмет. By default, 'inanimate'
51             # 5. 'prolog' key -- Preposition (prologue) of numeral
52             # 6. 'epilog' key -- Epilogue of numeral
53             # 7. 'alt' key
54             # 8. 'ucfirst' key
55              
56             sub case_endings {
57 8 100   8 1 27 $! = 22, return unless defined wantarray;
58 7         16 my( $number, %cfg ) = @_;
59 7 100       16 return unless defined $number;
60              
61 6         18 my( $i, $ns, @s ) = &num2cardinal( $number, %cfg );
62              
63 6         17 splice @s, $i, $ns - $i + 1, $number;
64              
65 6         43 return join(' ', @s);
66             }
67              
68              
69             sub spelled_out_number {
70 3 100   3 1 11 $! = 22, return unless defined wantarray;
71 2         8 my( $number, %cfg ) = @_;
72 2 100       8 return unless defined $number;
73              
74 1         4 my( $i, $ns, @s ) = &num2cardinal( $number, %cfg );
75              
76 1         4 $s[$i] = '('.$s[$i];
77 1         5 $s[$ns] = $s[$ns].')';
78 1         3 splice @s, $i, 0, $number;
79              
80 1         7 return join(' ', @s);
81             }
82              
83              
84             sub _num_check {
85 1872     1872   3296 for( $_[0] ) {
86 1872         4214 s/\D+//g;
87 1872         3087 s/^0+/0/;
88 1872         2875 s/^0(?!0)//;
89             }
90             }
91              
92              
93             sub num2cardinal {
94 1874 100   1874 1 367709 $! = 22, return unless defined wantarray;
95 1873         6530 my( $number, %cfg ) = @_;
96 1873 100       3173 return unless defined $number;
97              
98 1872         3546 &_num_check( $number );
99              
100             # extreme index for:
101 1     1   575 use constant VXN => 5; # numbers from 5 to <1000
  1         2  
  1         78  
102 1     1   6 use constant TMMT => 6; # тысячи | миллионы | миллиарды | триллионы
  1         2  
  1         2824  
103              
104 1872   100     4347 my $gender = $cfg{'gender'} || 'masculine';
105 1872 100       10047 $gender = $gender=~/^\s*(m|f|n)/i ? @{{'m'=>'masculine', 'f'=>'feminine', 'n'=>'neuter'}}{lc $1} : 'masculine';
  1871         5986  
106              
107 1872   100     5101 my $case = $cfg{'case'} || 'nominative';
108 1872 100       5266 $case = $case=~/^\s*([ngdaip])/i ? $1 : 'n';
109              
110 1872   100     4117 my $multi = $cfg{'multi'} || 'singular';
111 1872 100       4092 $multi = $multi=~/^\s*[p1-9]/i ? 'plural' : 'singular';
112              
113 1872   100     3875 my $object = $cfg{'object'} || 'inanimate';
114 1872 100       3379 $object = $object=~/^\s*[a1-9]/i ? 'animate' : 'inanimate';
115              
116             # Preposition (prologue) of numeral
117 1872         3910 my $prolog = &_ref_prolog( \%cfg, \$case );
118              
119             # Epilogue of numeral
120 1872         4163 my $epilog = &_ref_epilog( $case, $multi, \%cfg, \$object, \$gender );
121              
122 1872 100       3241 unless( $number ) {
123 69 100       168 my $oy = exists( $cfg{'alt'}{0} ) ? 'у' : 'о';
124             my $zero = ($case =~/^a/i && $object =~/^animate/i ) ?
125             "н${oy}ля" :
126 69 100 100     247 @{{'n'=>"н${oy}ль", 'g'=>"н${oy}ля", 'd'=>"н${oy}лю", 'a'=>"н${oy}ль", 'i'=>"н${oy}лём", 'p'=>"н${oy}ле"}}{ $case };
  66         514  
127              
128             # Add the numeral
129 69         197 my @s = ( $zero );
130              
131             # Add the prolog to numeral
132 69         161 my $ii = &_add_prolog( $prolog, \@s );
133 69         120 my $ns = $#s;
134              
135             # Add the epilog to numeral
136 69 100       147 if( exists $epilog->{'root'} ) {
137 29         44 my $j = 0;
138 29         36 for my $root ( @{ $epilog->{'root'} } ) {
  29         64  
139 36         104 push @s, $root.$epilog->{'ends'}[ $j++ ][0];
140             }
141             }
142              
143 69 100       201 $s[$ii] = ucfirst $s[$ii] if exists $cfg{'ucfirst'};
144              
145 69 100       6358 return wantarray ? ( $ii, $ns, @s ) : join(' ', @s);
146             }
147              
148 1803 100       3132 return "$number > 999_999_999_999_999 !" if length( $number ) > 15;
149              
150             # To get cardinal form DB (БД словоформ числительных)
151 1802         3335 my( $bsw, $plural, $Power ) = &_cardinal_form_db( $case, $multi, $object, $gender, \%cfg );
152              
153 1802         2773 my @Dcml = @{ $bsw->{'dcml'} };
  1802         4398  
154 1802         2465 my @Cent = @{ $bsw->{'cent'} };
  1802         3554  
155              
156 1802         4498 my @tmEnd; # for ends --- для окончаний 'тысяч','миллион','миллиард','триллион'
157             my @words; # for ends --- для искомой структуры слов числительных
158 1802         0 my @s; # Resulting string --- Результирующая строка
159 1802         0 my $ns; # size of numeral string
160              
161 1802   100     5124 while( length( $number ) && $number ) {
162 3724 100       7499 if( $number =~/^.$/ ) { # 0..9
163              
164             push @s, ( $multi =~/^plural/i && $number == 1 ) ?
165             $plural->{1} :
166 430 100 100     2058 $bsw->{ $gender }{ ($case =~/^a/i && $object =~/^animate/i) ? 'animate' : 'unit'}[ $number ];
    100 100        
167              
168             # Add epilog to numeral
169 430 100       838 if( exists $epilog->{'root'} ) {
170              
171 180         223 my $j = 0;
172 180         203 for my $root ( @{ $epilog->{'root'} } ) {
  180         318  
173 212 100       634 push @s, $root.$epilog->{'ends'}[ $j++ ][ $number < 5 ? $number : VXN ];
174             }
175 180         255 $ns = $j;
176              
177 180         291 $epilog = {}; # epilog END
178             }
179              
180 430         763 last;
181             }
182              
183 3294         5587 my $i = int length( $number ) / 3;
184              
185 3294 100       4937 if( $i < 2 ) { # $number = 10 .. 99_999
186             # Женский род, (т.к. может быть 'тысяч')
187 1364         1541 @words = @{ $bsw->{'feminine'}{'unit'} };
  1364         4114  
188 1364         1532 @tmEnd = @{ $bsw->{'eT'} }; # окончания для 'тысяч'
  1364         2330  
189             }
190             else { # Для >=100_000, 'миллион','миллиард','триллион'
191             # Мужской род
192 1930         2060 @words = @{ $bsw->{'masculine'}{'unit'} };
  1930         5892  
193 1930         2202 @tmEnd = @{ $bsw->{'eMT'} }; # окончания
  1930         3123  
194             }
195              
196 3294 100       6287 if( length( $number )%3 == 0 ) { # Сотни: 100 .. 999, 100_xxx .. 999_xxx, 100_xxx_xxx .. 999_xxx_xxx, etc.
    100          
197 771         1998 $number =~s/^\d//;
198 771 100       3214 push @s, $Cent[$&] if $&;
199             }
200             elsif( length( $number )%3 == 2 ) { # Десятки: 10 .. 99, 10_xxx .. 99_xxx, 10_xxx_xxx .. 99_xxx_xxx, etc.
201 1180 100       2065 if( $number =~/^1/ ) { # 10... 19...
202 276         715 $number =~s/^\d\d//;
203 276         783 push @s, $words[$&];
204              
205 276 100       944 push @s, $Power->[$i].$tmEnd[0] if length $Power->[$i];
206             }
207             else { # 00, 20... 99...
208 904         2057 $number =~s/^\d//;
209 904 100       3422 push @s, $Dcml[$&] if $&;
210             }
211             }
212             else { # length( $number )%3 == 1 # Единицы: 0..., 1,..., 9...
213 1343         3441 $number =~s/^\d//;
214 1343         2547 my $d = $&;
215 1343 100       2175 if( $d ) {
216 951 100 100     2981 push @s, ( $multi =~/^plural/i && $d == 1 ) ? $plural->{1} : $words[$d];
217             }
218              
219 1343 100       3610 if( $s[-1] !~/^(?:м|трил)/ ) { # ещё не добавлено миллион | миллиард | триллион
220             my $w = ( $multi =~/^plural/i && $d == 1 ) ?
221 1196 100 100     3521 $plural->{ $i < 2 ? 'eT' : 'eMT'} :
    100          
    100          
222             $tmEnd[ $d < 5 ? $d : 0 ];
223              
224 1196         2648 push @s, $Power->[$i].$w;
225             }
226              
227 1343 100       4429 last if $number =~/^0+$/;
228             }
229             }
230              
231             # Add prolog to numeral
232 1802         3377 my $ii = &_add_prolog( $prolog, \@s );
233 1802 100       3289 $ns = ( defined $ns ) ? $#s - $ns : $#s;
234              
235 1802 100       3747 $s[$ii] = ucfirst $s[$ii] if exists $cfg{'ucfirst'};
236              
237             # Add epilog to numeral
238 1802 100       2852 if( exists $epilog->{'root'} ) {
239              
240             # Choice between
241 387 100       1157 my $k = $s[-1] =~/^(?:ты|ми|трил)/ ?
242             TMMT : # тысяча | миллион | миллиард | триллион
243             VXN; # other
244              
245 387         551 my $j = 0;
246 387         470 for my $root ( @{ $epilog->{'root'} } ) {
  387         735  
247 455         1170 push @s, $root.$epilog->{'ends'}[ $j++ ][ $k ];
248             }
249              
250             }
251              
252 1802 100       25913 return wantarray ? ( $ii, $ns, @s ) : join(' ', @s);
253             }
254              
255              
256             sub _cardinal_form_db {
257 1802     1802   3198 my( $case, $multi, $object, $gender, $cfg ) = @_;
258              
259             # База словоформ числительных (singular -- единственно число, default)
260 1802         83329 my %bsw = (
261             'n' => { # nominative (Именительный падеж) кто? что?, default
262             'masculine' => { # Мужской род, default
263             'unit' => [ # 0..19
264             '','один','два','три','четыре','пять','шесть','семь','восемь','девять','десять',
265             'одиннадцать','двенадцать','тринадцать','четырнадцать','пятнадцать','шестнадцать','семнадцать','восемнадцать','девятнадцать'
266             ],
267             },
268             'feminine' => { # Женский род
269             'unit' => [ # 0..19
270             '','одна','две' # остальные как для Мужского рода
271             ],
272             },
273             'neuter' => { # Средний род
274             'unit' => [ # 0..19
275             '','одно' # остальные как для Мужского рода
276             ],
277             },
278             'dcml' => [ # 20, 30,...,90
279             '','','двадцать','тридцать','сорок','пятьдесят','шестьдесят','семьдесят','восемьдесят','девяносто'
280             ],
281             'cent' => [ # 100..900
282             '','сто','двести','триста','четыреста','пятьсот','шестьсот','семьсот','восемьсот','девятьсот'
283             ],
284             'eT' => [ # окончания для 'тысяч' (0й - для 10..19; десятков: 10,20,...,90 и сотен: 100,200,...,900)
285             '','а', ('и') x 3 # , ('') x 5
286             ],
287             'eMT' => [ # окончания для 'миллион','миллиард','триллион' (0й - для 10..19; десятков: 10,20,...,90 и сотен: 100,200,...,900)
288             'ов','', ('а') x 3 # , ('ов') x 5
289             ],
290             }, #--------------------------------------------
291             'g' => { # genitive (Родительный падеж): кого? чего?
292             'masculine' => { # Мужской род, default
293             'unit' => [ # 0..19
294             '','одного','двух','трёх','четырёх','пяти','шести','семи','восьми','девяти','десяти',
295             'одиннадцати','двенадцати','тринадцати','четырнадцати','пятнадцати','шестнадцати','семнадцати','восемнадцати','девятнадцати'
296             ],
297             },
298             'feminine' => { # Женский род
299             'unit' => [ # 0..19
300             '','одной' # остальные как для Мужского рода
301             ],
302             },
303             'neuter' => { # Средний род
304             'unit' => [ # 0..19
305             '' # всё как для Мужского рода
306             ],
307             },
308             'dcml' => [ # 20, 30,...,90
309             '','','двадцати','тридцати','сорока','пятидесяти','шестидесяти','семидесяти','восьмидесяти','девяноста'
310             ],
311             'cent' => [ # 100..900
312             '','ста','двухсот','трёхсот','четырёхсот','пятисот','шестисот','семисот','восьмисот','девятисот'
313             ],
314             'eT' => [ # окончания для 'тысяч'
315             '','и', ('') x 3 # 8
316             ],
317             'eMT' => [ # окончания для 'миллион','миллиард','триллион'
318             'ов','а', ('ов') x 3 # 8
319             ],
320             }, #--------------------------------------------
321             'd' => { # dative (Дательный падеж): кому? чему?
322             'masculine' => { # Мужской род, default
323             'unit' => [ # 0..19
324             '','одному','двум','трём','четырём','пяти','шести','семи','восьми','девяти','десяти',
325             'одиннадцати','двенадцати','тринадцати','четырнадцати','пятнадцати','шестнадцати','семнадцати','восемнадцати','девятнадцати'
326             ],
327             },
328             'feminine' => { # Женский род
329             'unit' => [ # 0..19
330             '','одной' # остальные как для Мужского рода
331             ],
332             },
333             'neuter' => { # Средний род
334             'unit' => [ # 0..19
335             '' # всё как для Мужского рода
336             ],
337             },
338             'dcml' => [ # 20, 30,...,90 : как Родительный падеж
339             '','','двадцати','тридцати','сорока','пятидесяти','шестидесяти','семидесяти','восьмидесяти','девяноста'
340             ],
341             'cent' => [ # 100..900
342             '','ста','двумстам','трёхстам','четырёхстам','пятистам','шестистам','семистам','восьмистам','девятистам'
343             ],
344             'eT' => [ # окончания для 'тысяч'
345             'ам','е', ('ам') x 3 # 8
346             ],
347             'eMT' => [ # окончания для 'миллион','миллиард','триллион'
348             'ам','у', ('ам') x 3 # 8
349             ],
350             }, #--------------------------------------------
351             'a' => { # accusative (Винительный падеж): animate (одушевлённый объект): кого? | inanimate (неодушевлённый объект): что?
352             'masculine' => { # Мужской род, inanimate default
353             'unit' => [ # 0..19 : неодушевлённый объект, как Именительный падеж
354             '','один','два','три','четыре','пять','шесть','семь','восемь','девять','десять',
355             'одиннадцать','двенадцать','тринадцать','четырнадцать','пятнадцать','шестнадцать','семнадцать','восемнадцать','девятнадцать'
356             ],
357             'animate' => [ # 0..19 : одушевлённый объект, как Родительный падеж (0..4), Именительный падеж (5..19)
358             '','одного','двух','трёх','четырёх', 'пять','шесть','семь','восемь','девять','десять',
359             'одиннадцать','двенадцать','тринадцать','четырнадцать','пятнадцать','шестнадцать','семнадцать','восемнадцать','девятнадцать'
360             ],
361             },
362             'feminine' => { # Женский род
363             'unit' => [ # 0..19 : неодушевлённый объект
364             '','одну','две' # остальные как для Мужского рода
365             ],
366             'animate' => [ # 0..19 : одушевлённый объект
367             '','одну' # остальные как для одушевлённого Мужского рода
368             ],
369             },
370             'neuter' => { # Средний род
371             'unit' => [ # 0..19 : неодушевлённый объект
372             '','одно' # остальные как для Мужского рода
373             ],
374             'animate' => [ # 0..19 : одушевлённый объект
375             '','одно','два' # остальные как для одушевлённого Мужского рода
376             ],
377             },
378             'dcml' => [ # 20, 30,...,90
379             '','','двадцать','тридцать','сорок','пятьдесят','шестьдесят','семьдесят','восемьдесят','девяносто'
380             ],
381             'cent' => [ # 100..900
382             '','сто','двести','триста','четыреста','пятьсот','шестьсот','семьсот','восемьсот','девятьсот'
383             ],
384             'eT' => [ # окончания для 'тысяч' (0й - для 10..19 и десятков: 10,20,...,90)
385             '','у', ('и') x 3 # , ('') x 5
386             ],
387             'eMT' => [ # окончания для 'миллион','миллиард','триллион' (0й - для 10..19 и десятков: 10,20,...,90)
388             'ов','', ('а') x 3 # , ('ов') x 5
389             ],
390             }, #--------------------------------------------
391             'i' => { # instrumental (Творительный падеж) : кем? чем?
392             'masculine' => { # Мужской род, default
393             'unit' => [ # 0..19
394             '','одним','двумя','тремя','четырьмя','пятью','шестью','семью','восемью','девятью','десятью', # or 'восьмью' (see p.22)
395             'одиннадцатью','двенадцатью','тринадцатью','четырнадцатью','пятнадцатью','шестнадцатью','семнадцатью','восемнадцатью','девятнадцатью'
396             ],
397             },
398             'feminine' => { # Женский род
399             'unit' => [ # 0..19
400             '','одной' # остальные как для Мужского рода
401             ],
402             'if1' => 'одною', # альтернативная форма
403             },
404             'dcml' => [ # 20, 30,...,90
405             '','','двадцатью','тридцатью','сорока','пятьюдесятью','шестьюдесятью','семьюдесятью','восемьюдесятью','девяноста' # or 'восьмьюдесятью' (see p.22)
406             ],
407             'cent' => [ # 100..900
408             '','ста','двумястами','тремястами','четырьмястами','пятьюстами','шестьюстами','семьюстами','восемьюстами','девятьюстами' # or 'восьмьюстами' (see p.22)
409             ],
410             'eT' => [ # окончания для 'тысяч'
411             'ами','ей', ('ами') x 3
412             # 'ами','ью', ('ами') x 3 # разговорная форма (see 'i.T'=>'C')
413             # 'ами','ею', ('ами') x 3 # устаревшая форма (see 'i.T'=>'O')
414             ],
415             'i.T' => { # формы окончания для 1 'тысяч'
416             'C' => 'ью', # разговорная (colloquial form)
417             'O' => 'ею', # устаревшая (obsolete form)
418             },
419             'eMT' => [ # окончания для 'миллион','миллиард','триллион'
420             'ами','ом', ('ами') x 3 # 8
421             ],
422             'i.8' => { # разговорные формы (see p.22)
423             'unit' => 'восьмью',
424             'dcml' => 'восьмьюдесятью',
425             'cent' => 'восьмьюстами',
426             },
427             }, #--------------------------------------------
428             'p' => { # prepositional (Предложный падеж) : о ком? о чём?
429             'masculine' => { # Мужской род, default
430             'unit' => [ # 0..19
431             '','одном','двух','трёх','четырёх','пяти','шести','семи','восьми','девяти','десяти',
432             'одиннадцати','двенадцати','тринадцати','четырнадцати','пятнадцати','шестнадцати','семнадцати','восемнадцати','девятнадцати'
433             ],
434             },
435             'feminine' => { # Женский род
436             'unit' => [ # 0..19
437             '','одной' # остальные как для Мужского рода
438             ],
439             },
440             'dcml' => [ # 20, 30,...,90
441             '','','двадцати','тридцати','сорока','пятидесяти','шестидесяти','семидесяти','восьмидесяти','девяноста'
442             ],
443             'cent' => [ # 100..900
444             '','ста','двухстах','трёхстах','четырёхстах','пятистах','шестистах','семистах','восьмистах','девятистах'
445             ],
446             'eT' => [ # окончания для 'тысяч'
447             'ах','е', ('ах') x 3 # 8
448             ],
449             'eMT' => [ # окончания для 'миллион','миллиард','триллион'
450             'ах','е', ('ах') x 3 # 8
451             ],
452             },
453             );
454              
455 1802         12975 my %plural = ( # множественное число
456             'n' => { # nominative (Именительный падеж)
457             1 => 'одни',
458             'eT' => 'и', # окончание для 'тысяч'
459             'eMT' => 'ы', # окончания для 'миллион','миллиард','триллион'
460             },
461             'g' => { # genitive (Родительный падеж)
462             1 => 'одних',
463             'eT' => '',
464             'eMT' => 'ов',
465             },
466             'd' => { # dative (Дательный падеж)
467             1 => 'одним',
468             'eT' => 'ам',
469             'eMT' => 'ам',
470             },
471             'a' => { # accusative (Винительный падеж):
472             1 => 'одни', # inanimate(неодушевлённый) объект. For animate(одушевлённый) -- see below
473             'eT' => 'и',
474             'eMT' => 'ы',
475             },
476             'i' => {# instrumental (Творительный падеж)
477             1 => 'одними',
478             'eT' => 'ами',
479             'eMT' => 'ами',
480             },
481             'p' => { # prepositional (Предложный падеж)
482             1 => 'одних',
483             'eT' => 'ах',
484             'eMT' => 'ах',
485             },
486             );
487              
488             # Дозаполняем необходимые структуры, кроме 'masculine'
489 1802         2922 my %gg = ('masculine' => undef );
490 1802         2705 for my $g ('feminine', $gender ) {
491 3604 100       6789 next if exists $gg{ $g };
492 2013         2655 $gg{ $g } = undef;
493              
494 2013         3226 for(0..19) {
495             # если НЕ определено
496 40260   100     115473 $bsw{ $case }{ $g }{'unit'}[$_] //= $bsw{ $case }{'masculine'}{'unit'}[$_];
497              
498 40260 100 66     86647 $bsw{'a'}{ $g }{'animate'}[$_] //= $bsw{'a'}{'masculine'}{'animate'}[$_]
      100        
499             if $case =~/^a/i && $object =~/^animate/i; # for accusative(Винительный падеж) + одушевлённый объект
500             }
501              
502             }
503              
504             # Настраиваем альтернативные | разговорные | устаревшие формы, если заданы
505 1802 100 100     3924 if( $case =~/^i/ and exists $cfg->{'alt'} ) {
506              
507 8         11 my $k = 'i.T'; # разговорная|устаревшая форма окончания для 'тысяч'
508 8 100 100     42 if( defined( $cfg->{'alt'}{ $k } ) and $cfg->{'alt'}{ $k } =~/^(C|O)/i ) {
509 3         10 $bsw{'i'}{'eT'}[1] = $bsw{'i'}{ $k }{uc $1};
510             }
511              
512 8         13 $k = 'i.8';
513 8 100       14 if( exists $cfg->{'alt'}{ $k } ) {
514 3         6 for('dcml','cent') { # 'восьмьюдесятью', 'восьмьюстами',
515 6         12 $bsw{'i'}{$_}[8] = $bsw{'i'}{ $k }{$_};
516             }
517              
518 3         4 my %gg;
519 3         5 for my $g ('masculine','feminine', $gender ) {
520 9 100       17 next if exists $gg{ $g };
521 6         8 $gg{ $g } = undef;
522              
523 6         9 $bsw{'i'}{ $g }{'unit'}[8] = $bsw{'i'}{ $k }{'unit'};# 'восьмью'
524             }
525             }
526              
527 8 100       17 $bsw{'i'}{'feminine'}{'unit'}[1] = $bsw{'i'}{'feminine'}{'if1'} if exists $cfg->{'alt'}{'if1'};
528             }
529              
530             # Корректируем окончания для accusative(Винительный падеж) + одушевлённый объект + множественное число
531 1802 100 100     4449 if( $case =~/^a/i && $object =~/^animate/i && $multi =~/^plural/i ) {
      100        
532 6         11 $plural{'a'}{1} = 'одних';
533 6         9 $plural{'a'}{'eT'} = '';
534 6         27 $plural{'a'}{'eMT'} = 'ов';
535             }
536              
537 1802         1998 return( \%{ $bsw{ $case } }, \%{ $plural{ $case } }, ['','тысяч','миллион','миллиард','триллион'] );
  1802         3273  
  1802         32409  
538             }
539              
540              
541             # Add prolog to numeral, e.g. ['с','со=ст',...]
542             sub _add_prolog {
543 1871     1871   2649 my( $prolog, $s ) = @_;
544 1871 100 100     5303 return 0 if ! @$prolog or (~~@$prolog < 2 and ( ! defined( $prolog->[0] ) or ! length( $prolog->[0] ) ) );
      100        
      100        
545              
546             # get element 0 in order (e.g. 'с') for any numeral
547 229 100 100     1248 my $p = ( !defined( $prolog->[0] ) or ! length( $prolog->[0] ) or $prolog->[0] =~/=/ ) ?
548             undef :
549             shift @$prolog;
550              
551             # get remaining elements
552 229         406 my $i = 0;
553 229         369 for( @$prolog ) { # ['со=ст',...]
554 147 100       253 next unless $_;
555              
556 145         446 my( $k, $m ) = split '=';
557 145 100 100     472 next unless $k && $m;
558              
559 143 100       697 if( $s->[0] =~/^$m/ ) {
560 47         114 unshift @$s, $k;
561 47         65 undef $p;
562 47         60 $i = 1;
563 47         80 last;
564             }
565             }
566              
567 229 100       443 if( defined $p ) {
568 180         331 unshift @$s, $p;
569 180         230 $i = 1;
570             }
571              
572 229         349 return $i;
573             }
574              
575              
576             sub _ref_prolog {
577 1872     1872   2635 my( $cfg, $case ) = @_;
578 1872   100     3893 my $prolog = $cfg->{'prolog'} // return [ ];
579              
580 1271 100       2744 if( ref($prolog) eq 'ARRAY') {
    100          
    100          
581 1066 100       2862 return ~~@$prolog ? [ @$prolog ] : [ ];
582             }
583             elsif( ref($prolog) eq 'HASH') {
584 3         5 my @p;
585 3         13 for my $k (sort keys %$prolog ) {
586 4         7 my $v = $prolog->{$k};
587 4         10 $k =~s/^\s+|\s+$//g;
588 4 100 100     17 next unless length $k or $v;
589              
590 3 100       8 if( length $v ) {
591 2         9 push @p, "$k=$v";
592             }
593             else {
594 1         3 unshift @p, $k;
595             }
596             }
597 3 100       13 return ~~@p ? \@p : [ ];
598             }
599             elsif( ref(\$prolog) eq 'SCALAR') {
600 201         598 $prolog =~s/^\s+|\s+$//g;
601              
602             # genitive - Родительный: кого? чего?
603 201 100       1017 if( $prolog =~/^(?:
604             безо?|
605             в(?:близи|виду|доль|замен|круг|место|не|низу|нутр[иь]|переди?|роде|овнутрь|озле|округ|следствие|ыше)|
606             для|до|
607             из(?:о?|\-за|нутри|\-подо?)|
608             каса(?:ем|тельн)о|кроме|кругом|
609             мимо|
610             на(?:кануне|место|подобие|против|супротив|счет)|ниже|
611             о(?:бок|бочь|коло|крест|круг|причь|то?|тносительно)|
612             по(?:близости|верх|дле|зад[иь]|мимо|перек|се?реди(?:не)?|середь|сле|средством)|
613             пр(?:евыше|отив)|путем|
614             ради|
615             с(?:верху?|выше|ередь|зади|илами|наружи|низу|переди|ред[иь]|упротив)|
616             у
617 1     1   7 )$/ix
  1         2  
  1         11  
618             ) {
619 6         10 $$case = 'g'; # genitive
620 6         16 return [ $prolog ];
621             }
622              
623             # dative - Дательный: кому? чему?
624 195 100       765 if( $prolog =~ /^(?:
    100          
625             вдогон(?:ку|очку)?|вослед|вразрез|вслед|
626             ко?|
627             напере(?:кор|рез)|
628             подобно|противно|
629             соо(?:браз|тветствен)но|соразмерно
630             )$/ix
631             ) {
632 6         10 $$case = 'd'; # dative
633 6         16 return [ $prolog ];
634             }
635             elsif( $prolog =~ /^благодаря$/i ) {
636 3 100       10 $$case = 'd' if $$case !~/^[d]/;
637 3         10 return [ $prolog ];
638             }
639              
640             # accusative - Винительный: кого? что?
641 186 100       403 if( $prolog =~ /^(?:
642             (?:вы?|ис)ключая|про|сквозь|спустя|че?рез
643             )$/ix
644             ) {
645 6         12 $$case = 'a'; # accusative
646 6         14 return [ $prolog ];
647             }
648              
649             # instrumental - Творительный: кем? чем?
650 180 100       364 if( $prolog =~ /^(?:
651             кончая|надо?|начиная|передо?|по\-[зн]ад?
652             )$/ix
653             ) {
654 6         13 $$case = 'i'; # instrumental
655 6         15 return [ $prolog ];
656             }
657              
658             # prepositional - Предложный: о ком? о чём?
659 174 100       315 if( $prolog =~ /^при$/i ) {
660 6         10 $$case = 'p'; # prepositional
661 6         18 return [ $prolog ];
662             }
663              
664             # genitive (Родительный) || dative (Дательный, by default)
665 168 100       304 if( $prolog =~ /^согласно$/i ) {
666 6 100       17 $$case = 'd' if $$case !~/^[gd]/;
667 6         19 return [ $prolog ];
668             }
669              
670             # genitive (Родительный, by default) || instrumental (Творительный)
671 162 100       265 if( $prolog =~ /^(?:про)?меж(?:ду)?$/i ) {
672 3 100       12 $$case = 'g' if $$case !~/^[gi]/;
673 3         10 return [ $prolog ];
674             }
675              
676             # accusative (Винительный) || instrumental (Творительный, by default)
677 159 100       286 if( $prolog =~ /^(?:за|подо?)$/i ) {
678 6 100       22 $$case = 'i' if $$case !~/^[ai]/;
679 6         16 return [ $prolog ];
680             }
681              
682             # accusative (Винительный) || prepositional (Предложный)
683 153 100       696 if( $prolog =~/^[вВB][ОоOo]?$/ ) {
    100          
    100          
684 4         20 $prolog =~tr/BOo/ВОо/;
685 4 100       15 $$case = 'a' if $$case !~/^[ap]/;
686 4         12 return [ $prolog ];
687             }
688             elsif( $prolog =~ /^[oOоО][бБ]?[oOоО]?$/ ) {
689 66 100       180 $$case = 'p' if $$case !~/^[ap]/;
690 66         186 return ['о','об=од'];
691             }
692             elsif( $prolog =~ /^на$/i ) {
693 4 100       14 $$case = 'a' if $$case !~/^[ap]/;
694 4         13 return [ $prolog ];
695             }
696              
697             # accusative (Винительный) || genitive (Родительный) || instrumental (Творительный, by default)
698 79 100       233 if( $prolog =~/^[cCсС][ОоOo]?$/ ) {
699 75 100       185 $$case = 'i' if $$case !~/^[agi]/;
700 75         215 return ['с','со=ст'];
701             }
702              
703             # accusative (Винительный) || dative (Дательный, by default) || prepositional (Предложный)
704 4 100       15 if( $prolog =~ /^по$/i ) {
705 3 100       9 $$case = 'd' if $$case !~/^[adp]/;
706 3         9 return [ $prolog ];
707             }
708              
709             }
710              
711 2         5 return [ ];
712             }
713              
714              
715             sub _ref_epilog {
716 1872     1872   3118 my( $case, $multi, $cfg, $object, $gender ) = @_;
717 1872 100       3719 my $epilog = $cfg->{'epilog'} or return {};
718              
719 1703 100 100     5955 if( ref(\$epilog) eq 'SCALAR') {
    100 66        
720 575         732 my %eRef;
721              
722 575 100       2696 if( $epilog =~/^(?:RU[BR]|643|810|₽|(?i:рубль|ruble))$/ ) { # Российский рубль
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
723 153         1689 %eRef = (
724             'object' => 'inanimate',
725             'gender' => 'masculine',
726             'root' => 'рубл',
727             'ends' => {
728             'n' => ['ей','ь', ('я') x 3, ('ей') x 2 ], # nominative - Именительный
729             'g' => ['ей','я', ('ей') x 5 ], # genitive - Родительный
730             'd' => ['ям','ю', ('ям') x 4, 'ей' ], # dative - Дательный
731             'a' => ['ей','ь', ('я') x 3, ('ей') x 2 ], # accusative - Винительный
732             'i' => ['ей','ём', ('ями') x 4, 'ей' ], # instrumental - Творительный
733             'p' => ['ей','е', ('ях') x 4, 'ей' ], # prepositional - Предложный
734             },
735             'plural' => {'n'=>'и', 'g'=>'ей', 'd'=>'ям', 'a'=>'и', 'i'=>'ями', 'p'=>'ях'},
736             );
737              
738             }
739             elsif( $epilog =~/^(?:BY[BRN]|Br|933|974)$/) { # Белорусский рубль
740 98         1784 %eRef = (
741             'object' => 'inanimate',
742             'gender' => 'masculine',
743             'root' => ['белорусск','рубл'],
744             'ends' => {
745             'n' => [['их','ий', ('их') x 5 ], ['ей','ь', ('я') x 3, ('ей') x 2 ]], # nominative - Именительный
746             'g' => [['их','ого', ('их') x 5 ], ['ей','я', ('ей') x 5 ]], # genitive - Родительный
747             'd' => [['им','ому', ('им') x 4, 'их'], ['ям','ю', ('ям') x 4, 'ей' ]], # dative - Дательный
748             'a' => [['их','ий', ('их') x 5 ], ['ей','ь', ('я') x 3, ('ей') x 2 ]], # accusative - Винительный
749             'i' => [['их','им', ('ими') x 4, 'их'], ['ей','ём', ('ями') x 4, 'ей']], # instrumental - Творительный
750             'p' => [['их','ом', ('их') x 5], ['ей','е', ('ях') x 4, 'ей']], # prepositional - Предложный
751             },
752             'plural' => {'n'=>['ие','и'], 'g'=>['их','ей'], 'd'=>['им','ям'], 'a'=>['ие','и'], 'i'=>['ими','ями'], 'p'=>['их','ях']},
753             );
754              
755             }
756             elsif( $epilog =~/^(?:ru[br]|\-643|\-810|by[brn]|\-933|\-974|(?i:копейка|kopek))$/) { # Российская | Белорусская копейка
757 160         1690 %eRef = (
758             'object' => 'inanimate',
759             'gender' => 'feminine',
760             'root' => 'копе',
761             'ends' => {
762             'n' => ['ек','йка', ('йки') x 3, ('ек') x 2 ],
763             'g' => ['ек','йки', ('ек') x 5 ],
764             'd' => ['ек','йке', ('йкам') x 4, 'ек' ],
765             'a' => ['ек','йку', ('йки') x 3, ('ек') x 2 ],
766             'i' => ['ек','йкой', ('йками') x 4, 'ек' ],
767             'p' => ['ек','йке', ('йках') x 4, 'ек' ],
768             },
769             'plural' => {'n'=>'йки', 'g'=>'ек', 'd'=>'йкам', 'a'=>'йки', 'i'=>'йками', 'p'=>'йках'},
770             );
771              
772             }
773             elsif( $epilog =~/^(?:USD|840|(?:US)?\$|(?i:доллар|dollar))$/) {
774 149         1563 %eRef = (
775             'object' => 'inanimate',
776             'gender' => 'masculine',
777             'root' => 'доллар',
778             'ends' => {
779             'n' => ['ов','', ('а') x 3, ('ов') x 2 ],
780             'g' => ['ов','а', ('ов') x 5 ],
781             'd' => ['ам','у', ('ам') x 4, 'ов' ],
782             'a' => ['ов','', ('а') x 3, ('ов') x 2 ],
783             'i' => ['ов','ом', ('ами') x 4, 'ов' ],
784             'p' => ['ов','е', ('ах') x 4, 'ов' ],
785             },
786             'plural' => {'n'=>'ы', 'g'=>'ов', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
787             );
788              
789             }
790             elsif( $epilog =~/^(?:usd|\-840|(?i:цент|cent))$/) {
791 1         19 %eRef = (
792             'object' => 'inanimate',
793             'gender' => 'masculine',
794             'root' => 'цент',
795             'ends' => {
796             'n' => ['ов','', ('а') x 3, ('ов') x 2 ],
797             'g' => ['ов','а', ('ов') x 5 ],
798             'd' => ['ам','у', ('ам') x 4, 'ов' ],
799             'a' => ['ов','', ('а') x 3, ('ов') x 2 ],
800             'i' => ['ов','ом', ('ами') x 4, 'ов' ],
801             'p' => ['ов','е', ('ах') x 4, 'ов' ],
802             },
803             'plural' => {'n'=>'ы', 'g'=>'ов', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
804             );
805              
806             }
807             elsif( $epilog =~/^(?:CNY|RMB|156|(?i:юань|yuan))$/) {
808 3         53 %eRef = (
809             'object' => 'inanimate',
810             'gender' => 'masculine',
811             'root' => 'юан',
812             'ends' => {
813             'n' => ['ей','ь', ('я') x 3, ('ей') x 2 ],
814             'g' => ['ей','я', ('ей') x 5 ],
815             'd' => ['ям','ю', ('ям') x 5 ],
816             'a' => ['ей','ь', ('я') x 3, ('ей') x 2 ],
817             'i' => ['ей','ем', ('ями') x 4, 'ей' ],
818             'p' => ['ях','е', ('ях') x 4, 'ей' ],
819             },
820             'plural' => {'n'=>'и', 'g'=>'ей', 'd'=>'ям', 'a'=>'и', 'i'=>'ями', 'p'=>'ях'},
821             );
822              
823             }
824             elsif( $epilog =~/^(?:cny|rmb|-156|(?i:фынь))$/) {
825 1         18 %eRef = (
826             'object' => 'inanimate',
827             'gender' => 'masculine',
828             'root' => 'фын',
829             'ends' => {
830             'n' => ['ей','ь', ('я') x 3, ('ей') x 2 ],
831             'g' => ['ей','я', ('ей') x 5 ],
832             'd' => ['ям','ю', ('ям') x 5 ],
833             'a' => ['ей','ь', ('я') x 3, ('ей') x 2 ],
834             'i' => ['ей','ем', ('ями') x 4, 'ей' ],
835             'p' => ['ях','е', ('ях') x 4, 'ей' ],
836             },
837             'plural' => {'n'=>'и', 'g'=>'ей', 'd'=>'ям', 'a'=>'и', 'i'=>'ями', 'p'=>'ях'},
838             );
839              
840             }
841             elsif( $epilog =~/^(?:year|год|лет)$/i) {
842 1         22 %eRef = (
843             'object' => 'inanimate',
844             'gender' => 'masculine',
845             'root' => '',
846             'ends' => {
847             'n' => ['лет','год', ('года') x 3, ('лет') x 2 ],
848             'g' => ['лет','года', ('лет') x 5 ],
849             'd' => ['лет','году', ('годам') x 4, 'лет' ],
850             'a' => ['лет','год', ('года') x 3, ('лет') x 2 ],
851             'i' => ['лет','годом', ('годами') x 4, 'лет' ],
852             'p' => ['лет','годе', ('годах') x 4, 'лет' ],
853             },
854             'plural' => {'n'=>'годы', 'g'=>'лет', 'd'=>'годам', 'a'=>'годы', 'i'=>'годами', 'p'=>'годах'},
855             );
856              
857             }
858             elsif( $epilog =~/^(?:month|месяц)$/i) {
859 1         20 %eRef = (
860             'object' => 'inanimate',
861             'gender' => 'masculine',
862             'root' => 'месяц',
863             'ends' => {
864             'n' => ['ев','', ('а') x 3, ('ев') x 2 ],
865             'g' => ['ев','а', ('ев') x 5 ],
866             'd' => ['ам','у', ('ам') x 5 ],
867             'a' => ['ев','', ('а') x 3, ('ев') x 2 ],
868             'i' => ['ев','ем', ('ами') x 4, 'ев'],
869             'p' => ['ев','е', ('ах') x 4, 'ев'],
870             },
871             'plural' => {'n'=>'ы', 'g'=>'ев', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
872             );
873              
874             }
875             elsif( $epilog =~/^(?:day|день)$/i) {
876 1         20 %eRef = (
877             'object' => 'inanimate',
878             'gender' => 'masculine',
879             'root' => 'д',
880             'ends' => {
881             'n' => ['ней','ень', ('ня') x 3, ('ней') x 2 ],
882             'g' => ['ней','ня', ('ней') x 5 ],
883             'd' => ['ням','ню', ('ням') x 5 ],
884             'a' => ['ней','ень', ('ня') x 3, ('ней') x 2 ],
885             'i' => ['ней','нём', ('нями') x 4, 'ней'],
886             'p' => ['ней','не', ('нях') x 4, 'ней'],
887             },
888             'plural' => {'n'=>'ни', 'g'=>'ней', 'd'=>'ням', 'a'=>'ни', 'i'=>'нями', 'p'=>'нях'},
889             );
890              
891             }
892             elsif( $epilog =~/^(?:hour|час)$/i) {
893 1         19 %eRef = (
894             'object' => 'inanimate',
895             'gender' => 'masculine',
896             'root' => 'час',
897             'ends' => {
898             'n' => ['ов','', ('а') x 3, ('ов') x 2 ],
899             'g' => ['ов','а', ('ов') x 5 ],
900             'd' => ['ам','у', ('ам') x 5 ],
901             'a' => ['ов','', ('а') x 3, ('ов') x 2 ],
902             'i' => ['ов','ом', ('ами') x 4, 'ов'],
903             'p' => ['ов','е', ('ах') x 4, 'ов'],
904             },
905             'plural' => {'n'=>'ы', 'g'=>'ов', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
906             );
907              
908             }
909             elsif( $epilog =~/^(?:min|мин)/i) {
910 1         19 %eRef = (
911             'object' => 'inanimate',
912             'gender' => 'feminine',
913             'root' => 'минут',
914             'ends' => {
915             'n' => ['','а', ('ы') x 3, ('') x 2 ],
916             'g' => ['','ы', ('') x 5 ],
917             'd' => ['','е', ('ам') x 4, ''],
918             'a' => ['','у', ('ы') x 3, ('') x 2 ],
919             'i' => ['','ой', ('ами') x 4, ''],
920             'p' => ['','е', ('ах') x 4, ''],
921             },
922             'plural' => {'n'=>'ы', 'g'=>'', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
923             );
924              
925             }
926             elsif( $epilog =~/^(?:sec|сек)/i) {
927 1         17 %eRef = (
928             'object' => 'inanimate',
929             'gender' => 'feminine',
930             'root' => 'секунд',
931             'ends' => {
932             'n' => ['','а', ('ы') x 3, ('') x 2 ],
933             'g' => ['','ы', ('') x 5 ],
934             'd' => ['','е', ('ам') x 4, ''],
935             'a' => ['','у', ('ы') x 3, ('') x 2 ],
936             'i' => ['','ой', ('ами') x 4, ''],
937             'p' => ['','е', ('ах') x 4, ''],
938             },
939             'plural' => {'n'=>'ы', 'g'=>'', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
940             );
941              
942             }
943             elsif( $epilog =~/^(?:meter|метр)$/i) {
944 1         19 %eRef = (
945             'object' => 'inanimate',
946             'gender' => 'masculine',
947             'root' => 'метр',
948             'ends' => {
949             'n' => ['ов','', ('а') x 3, ('ов') x 2 ],
950             'g' => ['ов','а', ('ов') x 5 ],
951             'd' => ['ов','у', ('ам') x 4, 'ов'],
952             'a' => ['ов','', ('а') x 3, ('ов') x 2 ],
953             'i' => ['ов','ом', ('ами') x 4, 'ов'],
954             'p' => ['ов','е', ('ах') x 4, 'ов'],
955             },
956             'plural' => {'n'=>'ы', 'g'=>'ов', 'd'=>'ам', 'a'=>'ы', 'i'=>'ами', 'p'=>'ах'},
957             );
958              
959             }
960             elsif( $epilog =~/^(?:stamp|печат)/i) {
961 1         21 %eRef = (
962             'object' => 'inanimate',
963             'gender' => 'feminine',
964             'root' => 'печат',
965             'ends' => {
966             'n' => ['ей','ь', ('и') x 3, ('ей') x 2 ],
967             'g' => ['ей','и', ('ей') x 5 ],
968             'd' => ['ей','и', ('ям') x 4, 'ей'],
969             'a' => ['ей','ь', ('и') x 3, ('ей') x 2 ],
970             'i' => ['ей','ью', ('ями') x 4, 'ей'],
971             'p' => ['ей','и', ('ях') x 4, 'ей'],
972             },
973             'plural' => {'n'=>'и', 'g'=>'ей', 'd'=>'ям', 'a'=>'и', 'i'=>'ями', 'p'=>'ях'},
974             );
975              
976             }
977              
978 575 100       1235 if( %eRef ) {
979 573         987 $$object = $eRef{'object'};
980 573         817 $$gender = $eRef{'gender'};
981              
982             # To fix for plural '1' only
983 573 100       1296 if( $multi =~/^plural/i ) {
984 122 100       329 if( ref( \$eRef{'plural'}{ $case } ) eq 'SCALAR') {
985 92         186 $eRef{'ends'}{ $case }[1] = $eRef{'plural'}{ $case };
986             }
987             else { # if( ref( $eRef{'plural'}{ $case } ) eq 'ARRAY') # a lot of words in the epilogue
988 30         46 my $i = 0;
989 30         34 for( @{ $eRef{'plural'}{ $case } } ) {
  30         62  
990 60         109 $eRef{'ends'}{ $case }[ $i++ ][1] = $_;
991             }
992             }
993             }
994              
995 573         897 $epilog = {};
996              
997 573 100       1073 if( ref( \$eRef{'root'} ) eq 'SCALAR') {
998 475         1029 $epilog->{'root'} = [ $eRef{'root'} ];
999 475         2275 $epilog->{'ends'}[0] = $eRef{'ends'}{ $case };
1000             }
1001             else { # if( ref( $eRef{'root'} ) eq 'ARRAY') # a lot of words in the epilogue
1002 98         169 $epilog->{'root'} = $eRef{'root'};
1003 98         562 $epilog->{'ends'} = $eRef{'ends'}{ $case };
1004             }
1005             }
1006             else {
1007 2         4 $epilog = {};
1008             }
1009              
1010             }
1011             elsif( ref($epilog) eq 'HASH' and exists $epilog->{'root'} and exists $epilog->{'ends'} ) {
1012 23 100       55 if( defined $epilog->{'object'} ) {
1013 21 100       55 $$object = $epilog->{'object'}=~/^\s*[a1-9]/i ? 'animate' : 'inanimate';
1014             }
1015              
1016 21         76 $$gender = @{{'m'=>'masculine', 'f'=>'feminine', 'n'=>'neuter'}}{lc $1}
1017 23 100 100     127 if defined( $epilog->{'gender'} ) && $epilog->{'gender'} =~/^\s*(m|f|n)/i;
1018              
1019             }
1020             else {
1021 1105         1585 $epilog = {};
1022             }
1023              
1024 1703         2965 return $epilog;
1025             }
1026              
1027             1;
1028              
1029             __END__