Ordinal sparkles
Weekly challenge 179 — 22 August 2022
Week 179: 22 Aug 2022
You are given a positive number, $n. Write a script to spell the ordinal number.
11 => eleventh 62 => sixty-second 99 => ninety-ninth
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.
#!/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; }
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