File Coverage

blib/lib/Lingua/POL/Num2Word.pm
Criterion Covered Total %
statement 109 246 44.3
branch 38 150 25.3
condition 13 69 18.8
subroutine 21 28 75.0
pod 17 18 94.4
total 198 511 38.7


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; mode:folding; coding:utf-8 -*-
2              
3             package Lingua::POL::Num2Word;
4             # ABSTRACT: Perl module for converting numeric values into their Polish equivalents
5              
6 1     1   110491 use 5.16.0;
  1         4  
7 1     1   4 use utf8;
  1         1  
  1         11  
8 1     1   21 use warnings;
  1         1  
  1         62  
9              
10             # {{{ use block
11              
12 1     1   4 use vars qw($Idziesiatka);
  1         6  
  1         61  
13              
14 1     1   465 use lib $ENV{PMLIB_INC};
  1         715  
  1         7  
15              
16 1     1   478 use Carp;
  1         1  
  1         70  
17 1     1   480 use Export::Attrs;
  1         11411  
  1         11  
18              
19             # }}}
20             # {{{ var block
21             our $VERSION = '0.2603300';
22              
23             # }}}
24              
25             # {{{ new
26              
27             sub new {
28 1     1 1 238588 my $class = shift;
29 1   50     11 my $number = shift || '';
30 1         6 $Idziesiatka=0;
31              
32 1         2 my $self = {};
33 1         3 bless $self, $class;
34              
35 1 50       5 if( $number =~ /\d+/ ) {
36 0         0 return( $self->parse($number) );
37             }
38              
39 1         4 return( $self );
40             }
41              
42             # }}}
43             # {{{ parse
44              
45             sub num2pol_cardinal :Export {
46 0     0 0 0 my $number = shift;
47 0         0 my $obj = Lingua::POL::Num2Word->new();
48 0         0 return $obj->parse($number);
49 1     1   228 }
  1         3  
  1         6  
50              
51             sub parse :Export {
52 3     3 1 1658 my $self = shift;
53 3         7 my $number = shift;
54              
55 3         22 return( SLOWNIE($number,0) );
56 1     1   263 }
  1         2  
  1         3  
57              
58             # }}}
59             # {{{ currency
60              
61             sub currency {
62 0     0 1 0 my $self = shift;
63 0         0 my $number = shift;
64              
65 0         0 return( SLOWNIE($number,1) );
66             }
67              
68             # }}}
69             # {{{ SLOWNIE
70              
71             sub SLOWNIE {
72 3   100 3 1 12 my $Numer = shift // 0;
73 3         5 my $currency = shift;
74              
75 3         8 my ($temps, $tempd, $tempj, $zlote, $grosze, $Licznik, $grd, $grj, $MiejsceDz, $T_S, $SLOWNIE);
76              
77 3 100       8 if ($Numer == 0) {
78 1 50       4 if ($currency) {
79 0         0 $SLOWNIE = "zero zl zero gr";
80             } else {
81 1         2 $SLOWNIE = "zero";
82             }
83             }
84             else {
85 2 100 66     9 if ($Numer > 9999999999999.99 || $Numer < 0) {
86             #carp "out of range in $Numer";
87 1         3 $SLOWNIE = "out of range";
88             }
89             else {
90 1         7 $Numer = Trim($Numer);
91 1         3 $MiejsceDz = InStr($Numer);
92 1 50 33     6 if ($MiejsceDz > 0 && Right($Numer,2) ne "00") {
    50          
93 0 0       0 if ($currency) {
94 0         0 $grosze = Left(Mid($Numer, $MiejsceDz + 1)."00", 2);
95 0         0 $grd = Dziesiatki(Right($grosze, 2));
96 0 0       0 if ($Idziesiatka!=1) {
97 0         0 $grj = Jednostki(Right($grosze, 1));
98             }
99 0         0 $grosze = " ".$grd.$grj."gr";
100 0         0 $Numer = Trim(Left($Numer, $MiejsceDz - 1));
101             }
102             else {
103 0         0 carp "no decimals allowed in parse mode in $Numer";
104 0         0 $zlote = "no decimals allowed in parse mode in $Numer";
105             }
106             }
107             elsif ($currency) {
108 0         0 $grosze = " zero gr";
109             }
110 1 50 33     6 if ($Numer>0 && ($currency || !$MiejsceDz)) {
    0 33        
      0        
111 1         1 $Licznik = 1;
112 1         3 while ($Numer ne "") {
113 1         2 $tempj = "";
114 1   50     4 $temps = Setki(Right("000".$Numer, 3)) // '';
115 1   50     3 $tempd = Dziesiatki(Right("00".$Numer, 2)) // '';
116 1 50       2 if ($Idziesiatka!=1) {
117 1   50     2 $tempj = Jednostki(Right($Numer, 1)) // '';
118             }
119 1 50 0     2 if ($Licznik==1) {
    0 0        
    0          
120 1         2 $T_S = $temps.$tempd.$tempj;
121             }
122             elsif ($Licznik==2) {
123 0         0 $T_S = $temps.$tempd.$tempj.KTys($Numer);
124             } elsif ($Licznik==3||$Licznik==4||$Licznik==5) {
125 0         0 $T_S = $temps.$tempd.$tempj.KMil($Numer, $Licznik);
126             }
127 1   50     6 $zlote = $T_S.($zlote // '');
128              
129 1 50       3 if (length($Numer) > 3) {
130 0         0 $Numer = Left($Numer, length($Numer) - 3);
131 0         0 $Licznik++;
132             }
133             else {
134 1         3 $Numer = "";
135             }
136             }
137             } elsif ($currency || !$MiejsceDz) {
138 0         0 $zlote = "zero "
139             }
140 1 50 33     4 if ($Numer !~ /^\d+$/ or $Numer > -1) {
141 1 50       2 if ($currency) {
142 0         0 $SLOWNIE = $zlote."zl".$grosze;
143             } else {
144 1         1 $SLOWNIE = $zlote;
145             }
146             }
147             }
148             }
149              
150 3         12 return $SLOWNIE;
151             }
152              
153             # }}}
154             # {{{ KTys
155              
156             sub KTys {
157 0     0 1 0 my $Numer = shift;
158 0         0 my $KTys;
159 0         0 my $tys=Val(Right("000".$Numer, 3));
160              
161 0 0       0 if ($tys == 0) {
162 0         0 $KTys = "";
163             }
164             else {
165 0         0 $tys = Val(Right($Numer, 2));
166 0 0       0 if ($tys == 1) {
167 0         0 $KTys = "ąc ";
168             }
169             else {
170 0 0 0     0 if ($tys == 12 || $tys == 13 || $tys == 14) {
      0        
171 0         0 $KTys = "ęcy ";
172             }
173             else {
174 0         0 $tys = Val(Right($Numer, 1));
175             }
176 0 0 0     0 if ( $tys == 2 || $tys == 3 || $tys == 4) {
      0        
177 0         0 $KTys = "ące ";
178             }
179             else {
180 0         0 $KTys = "ęcy ";
181             }
182             }
183 0         0 $KTys = "tysi".$KTys;
184             }
185              
186 0         0 return $KTys;
187             }
188              
189             # }}}
190             # {{{ KMil
191              
192             sub KMil {
193 0     0 1 0 my ($Numer, $L)=@_;
194 0         0 my ($KMil,$mil);
195 0         0 my @RzadW;
196 0         0 $RzadW[3] = "milion";
197 0         0 $RzadW[4] = "miliard";
198 0         0 $RzadW[5] = "bilion";
199 0         0 $mil = Val(Right("000".$Numer, 3));
200 0 0       0 if ($mil == 0) {
201 0         0 $KMil = "";
202             }
203             else {
204 0         0 $mil = Val(Right($Numer, 2));
205 0 0       0 if ($mil == 1) {
206 0         0 $KMil = " ";
207             }
208             else {
209 0 0 0     0 if ($mil == 12 || $mil == 13 || $mil == 14) {
      0        
210 0         0 $KMil = "ów ";
211             }
212             else {
213 0         0 $mil = Val(Right($Numer, 1));
214 0 0 0     0 if ($mil == 2 || $mil == 3 || $mil == 4) {
      0        
215 0         0 $KMil = "y ";
216             } else {
217 0         0 $KMil = "ów ";
218             }
219             }
220             }
221 0         0 $KMil = $RzadW[$L].$KMil;
222             }
223              
224 0         0 return $KMil;
225             }
226              
227             # }}}
228             # {{{ Setki
229              
230             sub Setki {
231 1     1 1 2 my $Numer=shift;
232 1         2 my ($setka, $wynik);
233 1         3 $setka = Val(Left($Numer, 1));
234 1 50       11 if ($setka == 1) {
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
235 0         0 $wynik= "sto ";
236             } elsif ($setka == 2) {
237 0         0 $wynik = 'dwieście ';
238             } elsif ($setka == 3) {
239 0         0 $wynik = 'trzysta ';
240             } elsif ($setka == 4) {
241 0         0 $wynik = 'czterysta ';
242             } elsif ($setka == 5) {
243 0         0 $wynik = 'pięćset ';
244             } elsif ($setka == 6) {
245 0         0 $wynik = 'sześćset ';
246             } elsif ($setka == 7) {
247 1         1 $wynik = 'siedemset ';
248             } elsif ($setka == 8) {
249 0         0 $wynik = 'osiemset ';
250             } elsif ($setka == 9) {
251 0         0 $wynik = 'dziewięćset ';
252             } else {
253 0         0 $wynik = '';
254             }
255              
256 1         4 return $wynik;
257             }
258              
259             # }}}
260             # {{{ Dziesiatki
261              
262             sub Dziesiatki {
263 1     1 1 2 my $Number = shift;
264 1         2 my $wynik = '';
265              
266 1         2 $Idziesiatka = Val(Left($Number, 1));
267 1 50       3 if ($Idziesiatka == 1) {
268 0         0 my $valnum = Val($Number);
269 0 0       0 if ($valnum == 10) { $wynik = 'dziesięć '; }
  0 0       0  
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
270 0         0 elsif ($valnum == 11) { $wynik = 'jedenaście '; }
271 0         0 elsif ($valnum == 12) { $wynik = 'dwanaście '; }
272 0         0 elsif ($valnum == 13) { $wynik = 'trzynaście '; }
273 0         0 elsif ($valnum == 14) { $wynik = 'czternaście '; }
274 0         0 elsif ($valnum == 15) { $wynik = 'piętnaście '; }
275 0         0 elsif ($valnum == 16) { $wynik = 'szesnaście '; }
276 0         0 elsif ($valnum == 17) { $wynik = 'siedemnaście '; }
277 0         0 elsif ($valnum == 18) { $wynik = 'osiemnaście '; }
278 0         0 elsif ($valnum == 19) { $wynik = 'dziewiętnaście '; }
279             }
280             else {
281 1 50       7 if ($Idziesiatka == 2) { $wynik = 'dwadzieścia '; }
  0         0  
282 1 50       3 if ($Idziesiatka == 3) { $wynik = 'trzydzieści '; }
  0         0  
283 1 50       21 if ($Idziesiatka == 4) { $wynik = 'czterdzieści '; }
  0         0  
284 1 50       2 if ($Idziesiatka == 5) { $wynik = 'pięćdziesiąt '; }
  0         0  
285 1 50       2 if ($Idziesiatka == 6) { $wynik = 'sześćdziesiąt '; }
  0         0  
286 1 50       2 if ($Idziesiatka == 7) { $wynik = 'siedemdziesiąt '; }
  0         0  
287 1 50       2 if ($Idziesiatka == 8) { $wynik = 'osiemdziesiąt '; }
  0         0  
288 1 50       3 if ($Idziesiatka == 9) { $wynik = 'dziewięćdziesiąt '; }
  0         0  
289             }
290              
291 1         3 return $wynik;
292             }
293              
294             # }}}
295             # {{{ Jednostki
296              
297             sub Jednostki {
298 1     1 1 1 my $Numer=shift;
299 1         1 my ($jedst, $wynik);
300 1         3 $jedst = Val(Right($Numer, 1));
301 1 50       11 if ($jedst == 1) {
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
302 0         0 $wynik = "jeden ";
303             } elsif ($jedst == 2) {
304 0         0 $wynik = "dwa ";
305             } elsif ($jedst == 3) {
306 0         0 $wynik = "trzy ";
307             } elsif ($jedst == 4) {
308 0         0 $wynik = "cztery ";
309             } elsif ($jedst == 5) {
310 0         0 $wynik = "pięć ";
311             } elsif ($jedst == 6) {
312 0         0 $wynik = "sześć ";
313             } elsif ($jedst == 7) {
314 1         2 $wynik = "siedem ";
315             } elsif ($jedst == 8) {
316 0         0 $wynik = "osiem ";
317             } elsif ($jedst == 9) {
318 0         0 $wynik = "dziewięć ";
319             }
320 1         2 return $wynik;
321             }
322              
323             # }}}
324             # {{{ Left
325              
326             sub Left {
327 2     2 1 23 my ($Numer, $count) = @_;
328 2         3 $Numer = substr($Numer,0,$count);
329              
330 2         17 return $Numer;
331             }
332              
333             # }}}
334             # {{{ Right
335              
336             sub Right {
337 4     4 1 6 my ($Numer, $count) = @_;
338 4         7 $Numer = substr($Numer,-$count);
339              
340 4         10 return $Numer;
341             }
342              
343             # }}}
344             # {{{ Trim
345              
346             sub Trim {
347 1     1 1 2 my $Numer = shift;
348 1         4 $Numer=~s/^\s+//;
349 1         3 $Numer=~s/\s+$//;
350              
351 1         3 return $Numer;
352             }
353              
354             # }}}
355             # {{{ Val
356              
357             sub Val {
358 3     3 1 3 my $Numer = shift;
359              
360 3         5 $Numer=~s/\D//g;
361              
362 3         6 return $Numer;
363             }
364              
365             # }}}
366             # {{{ Mid
367              
368             sub Mid {
369 0     0 1 0 my ($Numer, $count) = @_;
370              
371 0         0 return ($Numer = substr($Numer,$count-1));
372             }
373              
374             # }}}
375             # {{{ InStr
376              
377             sub InStr {
378 1     1 1 1 my $Numer = shift;
379 1         1 my $ret=0;
380 1 50       4 if ($Numer=~/^(\d+)\./) {
381 0         0 $ret=length($1)+1;
382             }
383              
384 1         1 return $ret;
385             }
386              
387             # }}}
388              
389              
390             # {{{ num2pol_ordinal number to ordinal string conversion
391              
392             sub num2pol_ordinal :Export {
393 0     0 1   my $number = shift;
394              
395 0 0 0       croak 'You should specify a number from interval [0, 999_999_999]'
      0        
      0        
396             if !defined $number
397             || $number !~ m{\A\d+\z}xms
398             || $number < 0
399             || $number > 999_999_999;
400              
401             # Irregular ordinals 0-19
402 0           my %base = (
403             0 => 'zerowy',
404             1 => 'pierwszy',
405             2 => 'drugi',
406             3 => 'trzeci',
407             4 => 'czwarty',
408             5 => 'piąty',
409             6 => 'szósty',
410             7 => 'siódmy',
411             8 => 'ósmy',
412             9 => 'dziewiąty',
413             10 => 'dziesiąty',
414             11 => 'jedenasty',
415             12 => 'dwunasty',
416             13 => 'trzynasty',
417             14 => 'czternasty',
418             15 => 'piętnasty',
419             16 => 'szesnasty',
420             17 => 'siedemnasty',
421             18 => 'osiemnasty',
422             19 => 'dziewiętnasty',
423             );
424              
425 0 0         return $base{$number} if exists $base{$number};
426              
427             # Tens ordinals
428 0           my %tens_ord = (
429             20 => 'dwudziesty',
430             30 => 'trzydziesty',
431             40 => 'czterdziesty',
432             50 => 'pięćdziesiąty',
433             60 => 'sześćdziesiąty',
434             70 => 'siedemdziesiąty',
435             80 => 'osiemdziesiąty',
436             90 => 'dziewięćdziesiąty',
437             );
438              
439             # Hundreds ordinals
440 0           my %hundreds_ord = (
441             100 => 'setny',
442             200 => 'dwusetny',
443             300 => 'trzechsetny',
444             400 => 'czterechsetny',
445             500 => 'pięćsetny',
446             600 => 'sześćsetny',
447             700 => 'siedemsetny',
448             800 => 'osiemsetny',
449             900 => 'dziewięćsetny',
450             );
451              
452             # For compound numbers, Polish uses: ordinal of each significant part
453             # 21 = "dwudziesty pierwszy", 100 = "setny", 125 = "sto dwudziesty piąty"
454             # For large numbers: cardinal prefix + ordinal of last significant part
455              
456 0 0         if ($number >= 1_000_000) {
457 0           my $millions = int($number / 1_000_000);
458 0           my $remainder = $number % 1_000_000;
459 0 0         if ($remainder == 0) {
460 0 0         return 'milionowy' if $millions == 1;
461 0           return SLOWNIE($millions, 0) . 'milionowy';
462             }
463 0           my $prefix = SLOWNIE($millions * 1_000_000, 0);
464 0           return $prefix . num2pol_ordinal($remainder);
465             }
466              
467 0 0         if ($number >= 1_000) {
468 0           my $thousands = int($number / 1_000);
469 0           my $remainder = $number % 1_000;
470 0 0         if ($remainder == 0) {
471 0 0         return 'tysięczny' if $thousands == 1;
472 0           return SLOWNIE($thousands, 0) . 'tysięczny';
473             }
474 0           my $prefix = SLOWNIE($thousands * 1_000, 0);
475 0           return $prefix . num2pol_ordinal($remainder);
476             }
477              
478 0 0         if ($number >= 100) {
479 0           my $h = int($number / 100) * 100;
480 0           my $remainder = $number % 100;
481 0 0         if ($remainder == 0) {
482 0           return $hundreds_ord{$h};
483             }
484             # Cardinal hundreds prefix + ordinal of remainder
485 0           my $cardinal_prefix = Setki(sprintf('%03d', $number));
486 0           return $cardinal_prefix . num2pol_ordinal($remainder);
487             }
488              
489             # 20-99 compound
490 0 0         if ($number >= 20) {
491 0           my $t = int($number / 10) * 10;
492 0           my $remainder = $number % 10;
493 0 0         if ($remainder == 0) {
494 0           return $tens_ord{$t};
495             }
496 0           return $tens_ord{$t} . ' ' . $base{$remainder};
497             }
498              
499             # Should not reach here
500 0           return;
501 1     1   2115 }
  1         2  
  1         4  
502              
503             # }}}
504              
505             # {{{ capabilities declare supported features
506              
507             sub capabilities {
508             return {
509 0     0 1   cardinal => 1,
510             ordinal => 1,
511             };
512             }
513              
514             # }}}
515             1;
516              
517             # {{{ POD
518              
519             =pod
520              
521             =encoding utf-8
522              
523             =head1 NAME
524              
525             Lingua::POL::Num2Word - Perl module for converting numeric values into their Polish equivalents
526              
527             =head1 VERSION
528              
529             version 0.2603300
530              
531             =head1 DESCRIPTION
532              
533             Number 2 word conversion in POL.
534              
535             This is PetaMem release in iso-639-3 namespace.
536              
537             =head1 SYNOPSIS
538              
539             use Lingua::POL::Num2Word;
540              
541             my $numbers = Lingua::POL::Num2Word->new;
542              
543             my $text = $numbers->parse( 123 );
544              
545             # prints 'sto dwadzieścia trzy'
546             print $text;
547              
548             my $currency = $numbers->currency ( 123.45 );
549              
550             # prints 'sto dwadzieścia trzy zl czterdzieści pięć gr'
551             print $currency;
552              
553             =head1 FUNCTIONS
554              
555             =over
556              
557             =item new
558              
559             Constructor
560              
561             =item parse
562              
563             Converts number into Polish
564              
565             =item Dziesiatki
566              
567             private
568              
569             =item InStr
570              
571             private
572              
573             =item Jednostki
574              
575             private
576              
577             =item KMil
578              
579             private
580              
581             =item KTys
582              
583             private
584              
585             =item Left
586              
587             private
588              
589             =item Mid
590              
591             private
592              
593             =item Right
594              
595             private
596              
597             =item SLOWNIE
598              
599             private
600              
601             =item Setki
602              
603             private
604              
605             =item Trim
606              
607             private
608              
609             =item Val
610              
611             private
612              
613             =item num2pol_ordinal
614              
615             Converts number to Polish ordinal (e.g. 1 => "pierwszy", 21 => "dwudziesty pierwszy").
616              
617             =item currency
618              
619             private
620              
621              
622             =item B (void)
623              
624             => href hashref indicating supported conversion types
625              
626             Returns a hashref of capabilities for this language module.
627              
628             =back
629              
630             =head1 KNOWN BUGS
631              
632             None, but that does not mean there are not any.
633              
634             =head1 AUTHORS
635              
636             initial coding:
637             Henrik Steffen Ecpan@topconcepts.deE
638             specification, maintenance:
639             Richard C. Jelinek Erj@petamem.comE
640             maintenance, coding (2025-present):
641             PetaMem AI Coding Agents
642              
643             =head1 LICENSE
644              
645             Original license is not known.
646             PetaMem added Perl 5 licesne as default.
647              
648             =cut
649              
650             # }}}