Peter
Peter Campbell Smith

Ordinal sparkles

Weekly challenge 179 — 22 August 2022

Week 179: 22 Aug 2022

Task 1

Task — Ordinal number spelling

You are given a positive number, $n. Write a script to spell the ordinal number.

Examples

11 => eleventh
62 => sixty-second
99 => ninety-ninth

Analysis

My solution is based on dividing the digits into 3s, eg 234, and converting them to words, eg two hundred and thirty-four and then adding 'thousands' or 'millions' as appropriate.

I then suffix 'th', and deal with the exceptions, eg 'ninth', not 'nineth'.

I special case zero and a billion, weed out invalid entries, and that's it - anything from 0 to a billion, which should be enough for most purposes.

Try it 

Try running the script with any input:



example: 12345

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2022-08-22
use utf8;     # Week 179 - task 1 - Ordinal number spelling
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

ordinal_number_spelling($_) for (0 .. 3, 8 .. 11, 14, 20, 44, 100, 321, 4321, 654321, 987654321, 1000000000, 3.14159);

sub ordinal_number_spelling {   

    my ($number, $digits, $words, $j, $piece);
    
    $number = shift;
    $words = 'invalid' if ($number > 10**9 or $number !~ m|^\d{0,9}$|);
    $words = 'zeroth' if $number == 0;
    $words = 'one billionth' if $number == 10**9;
    
    # make cardinal number
    unless (defined $words) {
        $words = '';
        $digits = sprintf('%09d', $number);
        for ($j = 0; $j <= 6; $j += 3) {
            $piece = three_digits(substr($digits, $j, 3));
            if ($piece) {
                $words .= $piece ;
                $words .= $j == 0 ? ' million ' : ($j == 3 ? ' thousand ' : '');
            }
        }
        $words =~ s|^\s+||;
        
        # convert to ordinal
        $words =~ s|\s*$|th|;
        $words =~ s|oneth$|first|;
        $words =~ s|twoth$|second|;
        $words =~ s|threeth$|third|;
        $words =~ s|fiveth$|fifth|;
        $words =~ s|eightth$|eighth|;
        $words =~ s|nineth$|ninth|;
        $words =~ s|tyth$|tieth|;
    }
    
    say qq[\nInput:  \$n = $number];
    say qq[Output: $words];
}
    
sub three_digits {

    my (@digits, @tens, @teens, $hundreds, $words, $number, $tens, $units, $hyphen);
    
    # converts 3-digit number to words
    @digits = (' ', qw[one two three four five six seven eight nine]);
    @teens = qw[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen];
    @tens = (' ', ' ', qw[twenty thirty forty fifty sixty seventy eighty ninety]);

    # hundreds
    $number = shift;
    $hundreds = int($number / 100);
    $words = $hundreds ? $digits[$hundreds] . ' hundred' : '';
    $number -= $hundreds * 100;
    
    # tens and units    
    if ($number) {
        $words = $words . ' and' if $hundreds != 0;     
        $tens = int($number / 10);
        $units = $number - 10 * $tens;
        if ($tens != 1) {
            $hyphen = ($units and $tens) ? '-' : '';
            $words = $words . ' ' . $tens[$tens] . $hyphen . $digits[$units];
        } else {
            $words = $words . ' ' . $teens[$units];
        }
    }
    return $words;
}

Output


Input:  $n = 0
Output: zeroth

Input:  $n = 1
Output: first

Input:  $n = 2
Output: second

Input:  $n = 3
Output: third

Input:  $n = 8
Output: eighth

Input:  $n = 9
Output: ninth

Input:  $n = 10
Output: tenth

Input:  $n = 11
Output: eleventh

Input:  $n = 14
Output: fourteenth

Input:  $n = 20
Output: twentieth

Input:  $n = 44
Output: forty-fourth

Input:  $n = 100
Output: one hundredth

Input:  $n = 321
Output: three hundred and twenty-first

Input:  $n = 4321
Output: four thousand three hundred and twenty-first

Input:  $n = 654321
Output: six hundred and fifty-four thousand three hundred
        and twenty-first

Input:  $n = 987654321
Output: nine hundred and eighty-seven million six hundred
        and fifty-four thousand three hundred and 
        twenty-first

Input:  $n = 1000000000
Output: one billionth

Input:  $n = 3.14159
Output: invalid

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain