File Coverage

blib/lib/Lingua/TUR/Num2Word.pm
Criterion Covered Total %
statement 28 62 45.1
branch 2 32 6.2
condition 4 41 9.7
subroutine 9 11 81.8
pod 3 3 100.0
total 46 149 30.8


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; eval: (folding-mode 1); coding:utf-8 -*-
2              
3             package Lingua::TUR::Num2Word;
4             # ABSTRACT: Number to word conversion in Turkish
5              
6 1     1   110153 use 5.16.0;
  1         3  
7 1     1   3 use utf8;
  1         1  
  1         10  
8 1     1   19 use warnings;
  1         1  
  1         48  
9              
10             # {{{ use block
11              
12 1     1   4 use Carp;
  1         3  
  1         61  
13 1     1   492 use Export::Attrs;
  1         10670  
  1         5  
14 1     1   692 use Readonly;
  1         3902  
  1         498  
15              
16             # }}}
17             # {{{ variable declarations
18              
19             my Readonly::Scalar $COPY = 'Copyright (c) PetaMem, s.r.o. 2002-present';
20             our $VERSION = '0.2603300';
21              
22             # }}}
23              
24             # {{{ num2tur_cardinal convert number to text
25              
26             sub num2tur_cardinal :Export {
27 2     2 1 161625 my $positive = shift;
28              
29 2 50 33     24 croak 'You should specify a number from interval [0, 999_999_999]'
      33        
      33        
30             if !defined $positive
31             || $positive !~ m{\A\d+\z}xms
32             || $positive < 0
33             || $positive > 999_999_999;
34              
35 2         8 my @ones = qw(sıfır bir iki üç dört beş altı yedi sekiz dokuz);
36 2         8 my @tens = qw(on yirmi otuz kırk elli altmış yetmiş seksen doksan);
37              
38 2 50 33     12 return $ones[$positive] if ($positive >= 0 && $positive < 10); # 0 .. 9
39 0 0 0       return $tens[$positive / 10 - 1] if ($positive >= 10 && $positive < 100 && $positive % 10 == 0); # 10,20,..,90
      0        
40              
41 0           my $out;
42             my $remain;
43              
44 0 0 0       if ($positive > 9 && $positive < 100) { # 11 .. 99
    0 0        
    0 0        
    0 0        
    0          
45 0           my $ten_idx = int($positive / 10);
46 0           $remain = $positive % 10;
47              
48 0           $out = $tens[$ten_idx - 1] . ' ' . $ones[$remain];
49             }
50             elsif ($positive == 100) { # 100
51 0           $out = 'yüz';
52             }
53             elsif ($positive > 100 && $positive < 1000) { # 101 .. 999
54 0           my $hun_idx = int($positive / 100);
55 0           $remain = $positive % 100;
56              
57 0 0         $out = $hun_idx == 1 ? 'yüz' : $ones[$hun_idx] . ' yüz';
58 0 0         $out .= $remain ? ' ' . num2tur_cardinal($remain) : '';
59             }
60             elsif ($positive >= 1000 && $positive < 1_000_000) { # 1000 .. 999_999
61 0           my $tho_idx = int($positive / 1000);
62 0           $remain = $positive % 1000;
63              
64 0 0         $out = $tho_idx == 1 ? 'bin' : num2tur_cardinal($tho_idx) . ' bin';
65 0 0         $out .= $remain ? ' ' . num2tur_cardinal($remain) : '';
66             }
67             elsif ($positive >= 1_000_000 && $positive < 1_000_000_000) { # 1_000_000 .. 999_999_999
68 0           my $mil_idx = int($positive / 1_000_000);
69 0           $remain = $positive % 1_000_000;
70              
71 0           $out = num2tur_cardinal($mil_idx) . ' milyon';
72 0 0         $out .= $remain ? ' ' . num2tur_cardinal($remain) : '';
73             }
74              
75 0           return $out;
76 1     1   7 }
  1         2  
  1         7  
77              
78             # }}}
79              
80             # {{{ num2tur_ordinal convert number to ordinal text
81              
82             sub num2tur_ordinal :Export {
83 0     0 1   my $number = shift;
84              
85 0 0 0       croak 'You should specify a number from interval [1, 999_999_999]'
      0        
      0        
86             if !defined $number
87             || $number !~ m{\A\d+\z}xms
88             || $number < 1
89             || $number > 999_999_999;
90              
91 0           my $cardinal = num2tur_cardinal($number);
92              
93             # Turkish ordinals: cardinal + suffix determined by vowel harmony.
94             # Suffix has two forms depending on whether the cardinal ends in
95             # a vowel or consonant:
96             # ends in consonant: ıncı / inci / uncu / üncü
97             # ends in vowel: ncı / nci / ncu / ncü
98             # Consonant softening: final "t" becomes "d" (dört -> dörd).
99              
100 0           $cardinal =~ s{dört\z}{dörd}xms;
101              
102 0           my $last_vowel = q{};
103 0 0         if ($cardinal =~ m{([aeıioöuü])[^aeıioöuü]*\z}xms) {
104 0           $last_vowel = $1;
105             }
106              
107 0           my $ends_in_vowel = $cardinal =~ m{[aeıioöuü]\z}xms;
108              
109 0           my %suffix_v = ( # after vowel: drop the leading harmony vowel
110             'a' => 'ncı', 'ı' => 'ncı',
111             'e' => 'nci', 'i' => 'nci',
112             'o' => 'ncu', 'u' => 'ncu',
113             'ö' => 'ncü', 'ü' => 'ncü',
114             );
115 0           my %suffix_c = ( # after consonant: full suffix with harmony vowel
116             'a' => 'ıncı', 'ı' => 'ıncı',
117             'e' => 'inci', 'i' => 'inci',
118             'o' => 'uncu', 'u' => 'uncu',
119             'ö' => 'üncü', 'ü' => 'üncü',
120             );
121              
122 0 0         my $suffix_table = $ends_in_vowel ? \%suffix_v : \%suffix_c;
123 0   0       my $suffix = $suffix_table->{$last_vowel} // 'inci';
124              
125 0           return $cardinal . $suffix;
126 1     1   661 }
  1         3  
  1         7  
127              
128             # }}}
129              
130              
131             # {{{ capabilities declare supported features
132              
133             sub capabilities {
134             return {
135 0     0 1   cardinal => 1,
136             ordinal => 1,
137             };
138             }
139              
140             # }}}
141             1;
142              
143             __END__