vbrtrmn has asked for the wisdom of the Perl Monks concerning the following question:

Hey,

I'm sorting a list of company names, some of which begin with thing such as: 1st, 11th, 3rd, 13th, 83rd, 11, 33, 1, 15.

What is the best way to convert those to: First, Eleventh, Third, Thirteenth, Eighty-Third, Eleven, Thirtythree, One, Fifteen?
--
paul

Edit Masem 2001-08-22 - Title change from "Numeric/Ordinal to Alphabetical Sort"

  • Comment on Converting ordinal numbers to words prior to sorting

Replies are listed 'Best First'.
Re: Numeric/Ordinal to Alphabetical Sort
by acid06 (Friar) on Aug 21, 2001 at 02:02 UTC
    Well... I found Lingua::EN::Numbers::Ordinate in CPAN which doesn't do exactly what you want, but might help you solving your problem.

    update: I just couldn't believe that there wasn't a module that did what you want, so I kept searching and just found Lingua::EN::Nums2Words which does exactly what you want.

    acid06
    perl -e "print pack('h*', 16369646), scalar reverse $="
Re: Numeric/Ordinal to Alphabetical Sort
by thpfft (Chaplain) on Aug 20, 2001 at 23:47 UTC

    Sifmole is right that Number::Spell will get you part of the way, but unfortunately it doesn't handle ordinals at all.

    My first thought was that you could just add a new set of mappings:

    1 => 'first', 2 => 'second', ... 12 => 'twelfth', ... 30 => 'thirtieth', ...

    And use those ones if the supplied digit includes one of those distinctive suffixes. But it doesn't quite work: you'd end up with 'thirtieth first' for '31st'. Making it treat the first digit of 30 differently to the same digit in 31 is actually kind of painful.

    But then it occurred to me that it's easier just to post-process the output of Number::Spell for those cases where you know it's an ordinal rather than a numeral. The word-ending translation is actually fairly regular, as these things go. Here's a first attempt:

    use Number::Spell; my %ord = ( one => 'first', two => 'second', three => 'third', four => 'fourth', five => 'fifth', six => 'sixth', en => 'enth', eight => 'eighth', nine => 'ninth', twelve => 'twelfth', ty => 'tieth', hundred => 'hundredth', thousand => 'thousandth', ion => 'ionth' ); my @list = qw(1st 11th 3rd 13th 83rd 11 33 1 15 1000000th); my @stringlist; foreach my $number (@list) { my $stringversion; if ($number =~ m/(\d+)(?:st|th|rd)$/i) { $stringversion = spell_number($1); $stringversion =~ s/($_)$/$ord{$_}/i for keys %ord; } else { $stringversion = spell_number($number); } push @stringlist,$stringversion; } print join(', ',@stringlist);

    Which prints:

    first, eleventh, third, thirteenth, eighty third, eleven, thirty three, one, fifteen, one millionth

    It's not very pretty, nor is it economical (it doesn't exit that for loop after a match, for example), but you get the idea. I believe this works for any figure that Number::Spell can handle, but i'm sure there's an exception somewhere that i haven't thought of.

Re: Numeric/Ordinal to Alphabetical Sort
by Sifmole (Chaplain) on Aug 20, 2001 at 22:31 UTC
Re: Numeric/Ordinal to Alphabetical Sort
by dragonchild (Archbishop) on Aug 20, 2001 at 22:40 UTC
    This isn't really a sorting question. If what you were concerned with would be the sorting, the way to do it would be:
    @company_names = map { s/^(\d+)\w*\s*/$1 / } @company_names;
    That way, you've stripped off all the annoying 'st', 'rd', 'th', etc.

    ------
    /me wants to be the brightest bulb in the chandelier!

    Vote paco for President!