File Coverage

blib/lib/Math/NumSeq/AlphabeticalLength.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyright 2012 Kevin Ryde
2              
3             # This file is part of Math-NumSeq-Alpha.
4             #
5             # Math-NumSeq-Alpha is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Math-NumSeq-Alpha is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Math-NumSeq-Alpha. If not, see .
17              
18             package Math::NumSeq::AlphabeticalLength;
19 1     1   2525 use 5.004;
  1         3  
  1         35  
20 1     1   4 use strict;
  1         2  
  1         33  
21 1     1   5 use List::Util 'min';
  1         11  
  1         100  
22              
23 1     1   5 use vars '$VERSION', '@ISA';
  1         2  
  1         65  
24             $VERSION = 2;
25 1     1   78461 use Math::NumSeq;
  0            
  0            
26             use Math::NumSeq::Base::IterateIth;
27             @ISA = ('Math::NumSeq::Base::IterateIth',
28             'Math::NumSeq');
29             *_is_infinite = \&Math::NumSeq::_is_infinite;
30              
31             use Lingua::Any::Numbers;
32              
33             # uncomment this to run the ### lines
34             #use Smart::Comments;
35              
36              
37             # use constant name => Math::NumSeq::__('...');
38             use constant description => Math::NumSeq::__('Length of i written out in words.');
39             use constant default_i_start => 1;
40             use constant characteristic_count => 1;
41             use constant characteristic_smaller => 1;
42             use constant characteristic_integer => 1;
43              
44             use constant::defer parameter_info_array => sub {
45             require Lingua::Any::Numbers;
46              
47             # Lingua::Any::Numbers version 0.44 excludes Lingua::Conlang::Numbers
48             # which is a front-end to various Esperanto etc, no need to do that here.
49             my @choices = sort(Lingua::Any::Numbers::available());
50             ### @choices
51              
52             # move 'EN' to the start, if it exists (which it should)
53             foreach my $i (0 .. $#choices) {
54             if ($choices[$i] eq 'EN') {
55             unshift @choices, splice(@choices, $i, 1);
56             last;
57             }
58             }
59             ### @choices
60              
61             return [
62             {
63             name => 'lang',
64             display => ('Language'),
65             type => 'string',
66             default => 'EN',
67             choices => \@choices,
68             width => 8,
69             # description => Math::NumSeq::__('...'),
70             },
71             {
72             name => 'number_type',
73             type => 'enum',
74             default => 'cardinal',
75             choices => ['cardinal','ordinal'],
76             choices_display => [Math::NumSeq::__('Cardinal'),
77             Math::NumSeq::__('Ordinal')],
78             # description => Math::NumSeq::__('...'),
79             },
80             {
81             name => 'conjunctions',
82             display => ('Conjunctions'),
83             type => 'boolean',
84             default => 1,
85             description => ('Whether to include conjunctions "and" or "et" in the words of the sequence.'),
86             },
87              
88             # Not through Lingua::Any::Numbers interface
89             # {
90             # name => 'gender',
91             # type => 'enum',
92             # default => 'M',
93             # choices => ['M','F','N'],
94             # # description => Math::NumSeq::__('...'),
95             # },
96             # {
97             # name => 'declension',
98             # type => 'enum',
99             # default => 'nominative',
100             # choices => ['nominative','genitive','dative','accusative','ablative'],
101             # # description => Math::NumSeq::__('...'),
102             # },
103             ];
104             };
105              
106             sub values_min {
107             my ($self) = @_;
108             ### values_min(): $self
109             my $i_start = $self->i_start;
110             return ($self->{'values_min'}
111             = min (map {$self->ith($_)||0}
112             $i_start .. $i_start + 20));
113             }
114              
115             #------------------------------------------------------------------------------
116             # cf A052360 en cardinal including spaces and hyphens
117             # A052363 new longest alpha
118             # A134629 first requiring n letters
119             # A006968 or A092196 Roman numerals, up to 4000
120             #
121             # A003078 (Danish) DK
122             # A001050 (Finnish) FI
123             # A001368 (Irish Gaelic) GA
124             # A051785 (Catalan) CA
125             # A056597 (Serbian or Croatian) SR
126             # A132984 (Latin) LA
127             # A140395 (Hindi) HI
128             # A053306 (Galego)
129             # A140396 (Welsh) CY
130             # A140438 (Tamil) TA
131             # A014656 (Bokmal) NB, was NO Lingua::NO::Num2Word
132             # A028292 (Nynorsk) NN
133              
134             # catalogued in Alpha.pm
135             my %oeis_anum
136             = ('en,cardinal,0,noand' => 'A005589',
137             'en,ordinal,1,noand' => 'A006944',
138              
139             # Lingua::CS::Num2Word doubtful ...
140             'cs,cardinal,1' => 'A010038', # Czech, Lingua::CS::Num2Word
141              
142             # Lingua::DE::Num2Word doubtful ...
143             # 'de,cardinal,1' => 'A007208', # German, Lingua::DE::Num2Word
144              
145             'eo,cardinal,0' => 'A057853', # Esperanto, Lingua::EO::Numbers
146              
147             'es,cardinal,0' => 'A011762', # Spanish, Lingua::ES::Numeros
148              
149             'fr,ordinal,1' => 'A006969', # French, Lingua::FR::Numbers
150             'fr,cardinal,0,incspaces' => 'A007005',
151              
152             'hu,cardinal,1' => 'A007292', # Hungarian, Lingua::HU::Numbers
153              
154             # Not quite, centottanta in A026858 vs centoottanta in Lingua
155             # 'it,cardinal,0' => 'A026858', # Italian, Lingua::IT::Numbers
156              
157             'ja,cardinal,0' => 'A030166', # Japanese Kanji, Lingua::JA::Numbers
158              
159             'nl,cardinal,1' => 'A090589', # Dutch, Lingua::NL::Numbers
160             # cf A007485 ij as one letter
161              
162             # Not sure about 11=ellve cf A014656(11)=6
163             # # Bokmal NO, lately code change to NB
164             # 'no,cardinal,1' => 'A014656', # Lingua::NO::Num2Word
165             #
166             # cf A028292 Nynorsk A028292(1)=3
167             # 'nn,cardinal,1' => 'A028292',
168              
169             'pl,cardinal,0' => 'A008962', # Polish, Lingua::PL::Numbers
170              
171             # Not quite, A057696 Brazilian Portuguese "catorze"
172             # whereas "quatorze" in Lingua::PT::Nums2Words
173             # 'pt,cardinal,1' => 'A057696', # Lingua::PT::Nums2Words
174             # cf A057697 including spaces
175              
176             # No, Lingua::RU::Number 0.05 is money amounts only.
177             # 'ru,cardinal,1' => 'A006994', # Russian, Lingua::RU::Number
178              
179             'sv,cardinal,0' => 'A059124', # Swedish, Lingua::SV::Numbers
180              
181             'tr,cardinal,1' => 'A057435', # Turkish, Lingua::TR::Numbers
182             );
183             sub oeis_anum {
184             my ($self) = @_;
185             ### oeis_anum: $self
186              
187             my $key = join(',',
188             $self->{lang},
189             $self->{number_type},
190             $self->i_start);
191             if (! $self->{'conjunctions'}) {
192             $key .= ',noand';
193             }
194             ### $key
195             return $oeis_anum{$key};
196             }
197              
198             #------------------------------------------------------------------------------
199              
200             my %conjunctions_word = (en => 'and',
201             fr => 'et',
202             );
203             sub new {
204             my $self = shift->SUPER::new(@_);
205              
206             my $lang = $self->{'lang'} = lc($self->{'lang'});
207              
208             if ($lang eq 'sv') {
209             my $str = Lingua::Any::Numbers::to_string (2, 'sv');
210             ### $str
211             if (length($str) == 4) {
212             # Lingua::SV::Numbers gives utf-8 bytes, mangle it down to chars
213             ### decode_chars mangle out utf8 ...
214             $self->{'decode_chars'} = sub {
215             $_[0] =~ s/\303./X/g;
216             };
217             }
218             }
219              
220             if (! $self->{'conjunctions'}) {
221             if (! defined $self->{'conjunctions_word'}) {
222             $self->{'conjunctions_word'} = $conjunctions_word{$lang}
223             }
224             }
225              
226             return $self;
227             }
228              
229             sub ith {
230             my ($self, $i) = @_;
231             ### AlphabeticalLength ith(): "$i"
232              
233             if (_is_infinite($i)) {
234             return undef;
235             }
236              
237             my $lang = $self->{'lang'};
238             my $str;
239             if ($self->{'number_type'} eq 'ordinal') {
240             $str = Lingua::Any::Numbers::to_ordinal ($i, $lang);
241             if ($str eq $i) {
242             # some modules without ordinal support return $i as numerals unchanged
243             return undef;
244             }
245              
246             } else {
247             if ($lang eq 'eo' && $i == 1) {
248             # HACK: avoid warn() from num2eo(1) in Lingua::EO::Numbers 0.03
249             $str = 'unu';
250             } else {
251             $str = Lingua::Any::Numbers::to_string ($i, $lang);
252             }
253             }
254             if (my $decode_chars = $self->{'decode_chars'}) {
255             $decode_chars->($str);
256             }
257             ### language: $self->{'lang'}
258             ### $str
259              
260             if (! $self->{'conjunctions'}) {
261             if ($self->{'lang'} eq 'en') {
262             $str =~ s/\b$self->{'conjunctions_word'}\b//ig;
263             }
264             }
265              
266             my $count = 0;
267             while ($str =~ /(\w|[^[:ascii:]])/g) {
268             $count += length($1);
269             }
270             ### $count
271             return $count;
272              
273             # ### letters only: $str
274             # counting whitespace ...
275             # $str =~ s/[^[:word:][:space:]]//g;
276             # return length($str);
277             }
278              
279             1;
280             __END__