Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | |
2 | require 5; | |
3 | package Lingua::EN::Numbers::Ordinate; | |
4 | use strict; | |
5 | # Time-stamp: "2000-08-24 16:45:48 MDT" | |
6 | use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION); | |
7 | require Exporter; | |
8 | @ISA = ('Exporter'); | |
9 | @EXPORT = ('ordinate'); | |
10 | @EXPORT_OK = ('ordsuf', 'th'); | |
11 | $VERSION = "0.01"; | |
12 | ||
13 | ########################################################################### | |
14 | ||
15 | =head1 NAME | |
16 | ||
17 | Lingua::EN::Numbers::Ordinate -- go from cardinal number (3) to ordinal ("3rd") | |
18 | ||
19 | =head1 SYNOPSIS | |
20 | ||
21 | use Lingua::EN::Numbers::Ordinate; | |
22 | print ordinate(4), "\n"; | |
23 | # prints 4th | |
24 | print ordinate(-342), "\n"; | |
25 | # prints -342nd | |
26 | ||
27 | # Example of actual use: | |
28 | ... | |
29 | for(my $i = 0; $i < @records; $i++) { | |
30 | unless(is_valid($record[$i]) { | |
31 | warn "The ", ordinate($i), " record is invalid!\n"; | |
32 | next; | |
33 | } | |
34 | ... | |
35 | } | |
36 | ||
37 | =head1 DESCRIPTION | |
38 | ||
39 | There are two kinds of numbers in English -- cardinals (1, 2, 3...), and | |
40 | ordinals (1st, 2nd, 3rd...). This library provides functions for giving | |
41 | the ordinal form of a number, given its cardinal value. | |
42 | ||
43 | =head1 FUNCTIONS | |
44 | ||
45 | =over | |
46 | ||
47 | =item ordinate(SCALAR) | |
48 | ||
49 | Returns a string consisting of that scalar's string form, plus the | |
50 | appropriate ordinal suffix. Example: C<ordinate(23)> returns "23rd". | |
51 | ||
52 | As a special case, C<ordinate(undef)> and C<ordinate("")> return "0th", | |
53 | not "th". | |
54 | ||
55 | This function is exported by default. | |
56 | ||
57 | =item th(SCALAR) | |
58 | ||
59 | Merely an alias for C<ordinate>, but not exported by default. | |
60 | ||
61 | =item ordsuf(SCALAR) | |
62 | ||
63 | Returns just the appropriate ordinal suffix for the given scalar | |
64 | numeric value. This is what C<ordinate> uses to actually do its | |
65 | work. For example, C<ordsuf(3)> is "rd". | |
66 | ||
67 | Not exported by default. | |
68 | ||
69 | =back | |
70 | ||
71 | The above functions are all prototyped to take a scalar value, | |
72 | so C<ordinate(@stuff)> is the same as C<ordinate(scalar @stuff)>. | |
73 | ||
74 | =head1 CAVEATS | |
75 | ||
76 | * Note that this library knows only about numbers, not number-words. | |
77 | C<ordinate('seven')> might just as well be C<ordinate('superglue')> | |
78 | or C<ordinate("\x1E\x9A")> -- you'll get the fallthru case of the input | |
79 | string plus "th". | |
80 | ||
81 | * As is unavoidable, C<ordinate(0256)> returns "174th" (because ordinate | |
82 | sees the value 174). Similarly, C<ordinate(1E12)> returns | |
83 | "1000000000000th". Returning "trillionth" would be nice, but that's an | |
84 | awfully atypical case. | |
85 | ||
86 | * Note that this library's algorithm (as well as the basic concept | |
87 | and implementation of ordinal numbers) is totally language specific. | |
88 | ||
89 | To pick a trivial example, consider that in French, 1 ordinates | |
90 | as "1ier", whereas 41 ordinates as "41ieme". | |
91 | ||
92 | =head1 STILL NOT SATISFIED? | |
93 | ||
94 | Bored of this...? | |
95 | ||
96 | use Lingua::EN::Numbers::Ordinate qw(ordinate th); | |
97 | ... | |
98 | print th($n), " entry processed...\n"; | |
99 | ... | |
100 | ||
101 | Try this bit of lunacy: | |
102 | ||
103 | { | |
104 | my $th_object; | |
105 | sub _th () { $th_object } | |
106 | ||
107 | package Lingua::EN::Numbers::Ordinate::Overloader; | |
108 | my $x; # Gotta have something to bless. | |
109 | $th_object = bless \$x; # Define the object now, which _th returns | |
110 | use Carp (); | |
111 | use Lingua::EN::Numbers::Ordinate (); | |
112 | sub overordinate { | |
113 | Carp::croak "_th should be used only as postfix!" unless $_[2]; | |
114 | Lingua::EN::Numbers::Ordinate::ordinate($_[1]); | |
115 | } | |
116 | use overload '&' => \&overordinate; | |
117 | } | |
118 | ||
119 | Then you get to do: | |
120 | ||
121 | print 3 & _th, "\n"; | |
122 | # prints "3rd" | |
123 | ||
124 | print 1 + 2 & _th, "\n"; | |
125 | # prints "3rd" too! | |
126 | # Because of the precedence of & ! | |
127 | ||
128 | print _th & 3, "\n"; | |
129 | # dies with: "th should be used only as postfix!" | |
130 | ||
131 | Kooky, isn't it? For more delightful deleria like this, see | |
132 | Damian Conway's I<Object Oriented Perl> from Manning Press. | |
133 | ||
134 | Kinda makes you like C<th(3)>, doesn't it? | |
135 | ||
136 | =head1 COPYRIGHT | |
137 | ||
138 | Copyright (c) 2000 Sean M. Burke. All rights reserved. | |
139 | ||
140 | This library is free software; you can redistribute it and/or | |
141 | modify it under the same terms as Perl itself. | |
142 | ||
143 | =head1 AUTHOR | |
144 | ||
145 | Sean M. Burke C<sburke@cpan.org> | |
146 | ||
147 | =cut | |
148 | ||
149 | ########################################################################### | |
150 | ||
151 | sub ordsuf ($) { | |
152 | return 'th' if not(defined($_[0])) or not( 0 + $_[0] ); | |
153 | # 'th' for undef, 0, or anything non-number. | |
154 | my $n = abs($_[0]); # Throw away the sign. | |
155 | return 'th' unless $n == int($n); # Best possible, I guess. | |
156 | $n %= 100; | |
157 | return 'th' if $n == 11 or $n == 12 or $n == 13; | |
158 | $n %= 10; | |
159 | return 'st' if $n == 1; | |
160 | return 'nd' if $n == 2; | |
161 | return 'rd' if $n == 3; | |
162 | return 'th'; | |
163 | } | |
164 | ||
165 | sub ordinate ($) { | |
166 | my $i = $_[0] || 0; | |
167 | return $i . ordsuf($i); | |
168 | } | |
169 | ||
170 | *th = \&ordinate; # correctly copies the prototype, too. | |
171 | ||
172 | ########################################################################### | |
173 | 1; | |
174 | ||
175 | __END__ |