File Coverage

blib/lib/Lingua/RU/Numeral.pm
Criterion Covered Total %
statement 267 267 100.0
branch 220 220 100.0
condition 73 76 96.0
subroutine 14 14 100.0
pod 3 3 100.0
total 577 580 99.4


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