Hello and welcome to our community! Is this your first visit?
Enjoy an ad free experience by logging in. Not a member yet? Register.

# Thread: Function to convert number to ordinal word

1. ## Function to convert number to ordinal word

I'm looking for a way to convert a number to an ordinal word, i.e.:

1 --> first
2 --> second
11 --> eleventh
12 --> twelfth
20 --> twentieth
21 --> twenty-first
22 --> twenty-second

...etc., .etc...

Any ideas? Thanks.

• I've seen several scripts like this:
http://www.phpro.org/examples/Conver...-to-Words.html

I wonder if there might be a built-in PHP function for that ...
haven't found it yet though.

• I found that script also when doing a Google search...but that script doesn't convert to the "ordinal word" equivalent -- just the "word" equivalent...

The single (and I stress "single") script that I did find that attempted to do this (via Google) is so littered with errors that I didn't want to attempt to fix it without first looking for a simpler solution. Looks like I might have to try to fix it though....

A built in PHP function would be great, but I didn't spot one either...

• Although limited in the size (number to string needs to be manually controlled at each 10 based exponential value), the ordinal is actually the easier part of it.

Ordinal only applies on the 10's and 1's digits. So thats a plus. Ordinals for 1, 2, and 3 are st, nd, and rd. All others between 0 and 9 inclusive are th (you'll need to decide the actual '0' value as either 'zero' or 'zeroth'; we'd need our grammer nazi to verify which are valid).
The leading digits are irrelevant with the exception being 10 through 19 which all have th ordinals (and generally need to be accommodated for particular rulesets - the alorigthm to convert 27 to 'twenty-seventh' is not the same as to convert 17 to 'seventeenth').

• You caught my imagination, and I'm now absolutely determined to do this!

I'm going to bed now, at 1:30am... Here's what I've come up with so far:

PHP Code:
``` error_reporting(E_ALL);/*I think the best way to do this, is to create an array grouped by thousands,cardinal style, and lookup/modify for ordinal style.*/class shortScale {    // Source: Wikipedia (http://en.wikipedia.org/wiki/Names_of_large_numbers)    private static \$scale = array('', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quattuordecillion', 'quindecillion', 'sexdecillion', 'septendecillion', 'octodecillion', 'noverndecillion', 'vigintillion');    private static \$digit = array('', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen');    private static \$digith = array('', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fiftheenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth');    private static \$ten = array('', '', 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety');    private static \$tenth = array('', '', 'twentieth', 'thirtieth', 'fortieth', 'fiftieth', 'sixtieth', 'seventieth', 'eightieth', 'ninetieth');    private static function floatToArray(\$number, &\$int, &\$frac) {        // Forced \$number as (string), effectively to avoid (float) inprecision        @list(, \$frac) = explode('.', \$number);        \$int = explode(',', number_format(ltrim(\$number, '0'), 0, '', ','));    }        private static function thousandToEnglish(\$number) {        // Gets numbers from 0 to 999 and returns the cardinal English    }    public static function cardinalToOrdinal(\$cardinal) {        // Finds the last word in the cardinal arrays and replaces it with        // the entry from the ordinal arrays, or appends "th"        \$words = explode(' ', \$cardinal);        \$last = &\$words[count(\$words)-1];        if (in_array(\$last, self::\$digit)) {            \$last = self::\$digith[array_search(\$last, self::\$digit)];        } elseif (in_array(\$last, self::\$ten)) {            \$last = self::\$tenth[array_search(\$last, self::\$ten)];        } elseif (substr(\$last, -2) != 'th') {            \$last .= 'th';        }        return implode(' ', \$words);    }    public static function toOrdinal(\$number) {        // Converts a xth format number to English. e.g. 22nd to twenty-second.        return self::cardinalToOrdinal(self::toCardinal(\$number));    }        public static function toCardinal(\$number) {        // Converts a number to English. e.g. 22 to twenty-two.        self::floatToArray(\$number, \$int, \$frac);        for(\$i=count(\$int)-1; \$i>-1; \$i--) {            echo(\$int[\$i]."\n");            // use thousandToEnglish to get an array per \$int array item and combine them with self::scale[\$i]        }        echo(implode(',',\$int)." and \$frac\n");     }}echo(shortScale::toOrdinal(12123456789.123));  ```

• ## The Following 2 Users Say Thank You to Lamped For This Useful Post:

chump2877 (10-26-2009), FWDrew (10-26-2009)

• Thanks to everyone's input on this topic, especially ComputerX who obviously spent some time thinking about how to solve this...

I used a conglomerate of code from different places (including ComputerX's) to come up with a class that will serve my purpose for now: Get the ordinal phrases for 1 to 999. It could be done better, but it's all I really have patience for right now...

Feel free to improve on the code if you like...

PHP Code:
``` <?class Number {    // Private Fields    private \$_digit = array('', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen');    private \$_digith = array('', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth');    private \$_ten = array('', '', 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety');    private \$_tenth = array('', '', 'twentieth', 'thirtieth', 'fortieth', 'fiftieth', 'sixtieth', 'seventieth', 'eightieth', 'ninetieth');        // Constants    const _HUNDRED = 'hundred';    const _MAXNUMLENGTH = 3;    // Public Methods    public function toOrdinal(\$number)     {             return \$this->cardinalToOrdinal(\$this->toCardinal(\$number));    }        // Private "Helper" Methods    private function cardinalToOrdinal(\$cardinal)     {        // Finds the last word in the cardinal arrays and replaces it with        // the entry from the ordinal arrays, or appends "th"        \$words = explode(' ', \$cardinal);        \$last = \$words[count(\$words)-1];        \$last_parts = explode('-', \$last);        \$last_part = \$last_parts[count(\$last_parts)-1];                if (in_array(\$last_part, \$this->_digit))         {            \$last_part = \$this->_digith[array_search(\$last_part, \$this->_digit)];        }         elseif (in_array(\$last_part, \$this->_ten))         {            \$last_part = \$this->_tenth[array_search(\$last_part, \$this->_ten)];        }         elseif (\$last_part == self::_HUNDRED)         {            \$last_part = self::_HUNDRED.'th';        }        \$last_parts[count(\$last_parts)-1] = \$last_part;        \$words[count(\$words)-1] = implode('-', \$last_parts);        return implode(' ', \$words);    }            private function toCardinal(\$number)     {        if (\$number < 1 || \$number > (int)(str_repeat('9', self::_MAXNUMLENGTH)))         {             throw new Exception("Number is out of range");        }         \$Hn = floor(\$number / 100);      /* Hundreds */         \$number -= \$Hn * 100;         \$Dn = floor(\$number / 10);       /* Tens */         \$n = \$number % 10;               /* Ones */         \$res = "";         if (\$Hn)         {             \$res .= (empty(\$res) ? "" : " ") .                 \$this->toCardinal(\$Hn) . " " . self::_HUNDRED;         }                if (\$Dn || \$n)         {             if (!empty(\$res))             {                 \$res .= " and ";             }             if (\$Dn < 2)             {                 \$res .= \$this->_digit[\$Dn * 10 + \$n];             }             else             {                 \$res .= \$this->_ten[\$Dn];                 if (\$n)                 {                     \$res .= "-" . \$this->_digit[\$n];                 }             }         }                 return \$res;    }}\$num = new Number;for (\$i=1; \$i<2000; \$i++){    try     {        echo \$num->toOrdinal(\$i) . '<br />';    }    catch(Exception \$ex)    {        die(\$ex->getMessage());    }}?> ```

• I'm really pleased you got something working. I've continued working on it for the sake of completion, and that I like having useful code snippets.

This example is perfect for numbers from 0 to 999, with an example of cardinal and ordinal useage. I don't put a hyphen in, as it requires extra processing from the cardinalToOrdinal function that I don't personally think is necessary.

I'll put in the scaling and update here, again, for completeness sake.

PHP Code:
``` error_reporting(E_ALL);class shortScale {    // Source: Wikipedia (http://en.wikipedia.org/wiki/Names_of_large_numbers)    private static \$scale = array('', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quattuordecillion', 'quindecillion', 'sexdecillion', 'septendecillion', 'octodecillion', 'noverndecillion', 'vigintillion');    private static \$digit = array('', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen');    private static \$digith = array('', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fiftheenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth');    private static \$ten = array('', '', 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety');    private static \$tenth = array('', '', 'twentieth', 'thirtieth', 'fortieth', 'fiftieth', 'sixtieth', 'seventieth', 'eightieth', 'ninetieth');    private static function floatToArray(\$number, &\$int, &\$frac) {        // Forced \$number as (string), effectively to avoid (float) inprecision        @list(, \$frac) = explode('.', \$number);        \$int = explode(',', number_format(ltrim(\$number, '0'), 0, '', ','));    }        static function thousandToEnglish(\$number) {        // Gets numbers from 0 to 999 and returns the cardinal English        \$hundreds = floor(\$number / 100);        \$tens = \$number % 100;        \$pre = (\$hundreds ? self::\$digit[\$hundreds].' hundred' : '');        if (\$tens < 20)            \$post = self::\$digit[\$tens];        else            \$post = trim(self::\$ten[floor(\$tens / 10)].' '.self::\$digit[\$tens % 10]);        if (\$pre && \$post) return \$pre.' and '.\$post;        return \$pre.\$post;    }    public static function cardinalToOrdinal(\$cardinal) {        // Finds the last word in the cardinal arrays and replaces it with        // the entry from the ordinal arrays, or appends "th"        \$words = explode(' ', \$cardinal);        \$last = &\$words[count(\$words)-1];        if (in_array(\$last, self::\$digit)) {            \$last = self::\$digith[array_search(\$last, self::\$digit)];        } elseif (in_array(\$last, self::\$ten)) {            \$last = self::\$tenth[array_search(\$last, self::\$ten)];        } elseif (substr(\$last, -2) != 'th') {            \$last .= 'th';        }        return implode(' ', \$words);    }    public static function toOrdinal(\$number) {        // Converts a xth format number to English. e.g. 22nd to twenty-second.        return self::cardinalToOrdinal(self::toCardinal(\$number));    }        public static function toCardinal(\$number) {        // Converts a number to English. e.g. 22 to twenty-two.        self::floatToArray(\$number, \$int, \$frac);        for(\$i=count(\$int)-1; \$i>-1; \$i--) {            echo(\$int[\$i]."\n");            // use thousandToEnglish to get an array per \$int array item and combine them with self::scale[\$i]        }        echo(implode(',',\$int)." and \$frac\n");     }}for (\$i=0; \$i<20; \$i++) {    \$r = rand(0,999);    \$cardinal = shortScale::thousandToEnglish(\$r);    echo(\$r.': '.\$cardinal.' -- '.shortScale::cardinalToOrdinal(\$cardinal)."\n");}  ```

• Right, I'm done.

Did you know that 13,052,149,762,014,642,176,925,499,392 is thirteen nonillion, fifty two octillion, one hundred and fourty nine sextillion, seven hundred and sixty two quintillion, fourteen quadrillion, six hundred and fourty two trillion, one hundred and seventy six billion, nine hundred and twenty five million, four hundred and ninety nine thousand and three hundred and ninety two?

Use:

PHP Code:
``` \$english = shortScale::toOrdinal(\$number); // 2 to second\$english = shortScale::toCardinal(\$number); // 2 to two  ```
The class:
PHP Code:
``` class shortScale {    // Source: Wikipedia (http://en.wikipedia.org/wiki/Names_of_large_numbers)    private static \$scale = array('', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quattuordecillion', 'quindecillion', 'sexdecillion', 'septendecillion', 'octodecillion', 'noverndecillion', 'vigintillion');    private static \$digit = array('', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen');    private static \$digith = array('', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fiftheenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth');    private static \$ten = array('', '', 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety');    private static \$tenth = array('', '', 'twentieth', 'thirtieth', 'fortieth', 'fiftieth', 'sixtieth', 'seventieth', 'eightieth', 'ninetieth');    private static function floatToArray(\$number, &\$int, &\$frac) {        // Forced \$number as (string), effectively to avoid (float) inprecision        @list(, \$frac) = explode('.', \$number);        if (\$frac || !is_numeric(\$number) || (strlen(\$number) > 60)) throw new Exception('Not a number or not a supported number type');        // \$int = explode(',', number_format(ltrim(\$number, '0'), 0, '', ',')); -- Buggy        \$int = str_split(str_pad(\$number, ceil(strlen(\$number)/3)*3, '0', STR_PAD_LEFT), 3);    }        private static function thousandToEnglish(\$number) {        // Gets numbers from 0 to 999 and returns the cardinal English        \$hundreds = floor(\$number / 100);        \$tens = \$number % 100;        \$pre = (\$hundreds ? self::\$digit[\$hundreds].' hundred' : '');        if (\$tens < 20)            \$post = self::\$digit[\$tens];        else            \$post = trim(self::\$ten[floor(\$tens / 10)].' '.self::\$digit[\$tens % 10]);        if (\$pre && \$post) return \$pre.' and '.\$post;        return \$pre.\$post;    }    private static function cardinalToOrdinal(\$cardinal) {        // Finds the last word in the cardinal arrays and replaces it with        // the entry from the ordinal arrays, or appends "th"        \$words = explode(' ', \$cardinal);        \$last = &\$words[count(\$words)-1];        if (in_array(\$last, self::\$digit)) {            \$last = self::\$digith[array_search(\$last, self::\$digit)];        } elseif (in_array(\$last, self::\$ten)) {            \$last = self::\$tenth[array_search(\$last, self::\$ten)];        } elseif (substr(\$last, -2) != 'th') {            \$last .= 'th';        }        return implode(' ', \$words);    }    public static function toOrdinal(\$number) {        // Converts a xth format number to English. e.g. 22nd to twenty-second.        return trim(self::cardinalToOrdinal(self::toCardinal(\$number)));    }        public static function toCardinal(\$number) {        // Converts a number to English. e.g. 22 to twenty-two.        self::floatToArray(\$number, \$int, \$frac);        \$int = array_reverse(\$int);        for(\$i=count(\$int)-1; \$i>-1; \$i--) {            \$englishnumber = self::thousandToEnglish(\$int[\$i]);            if (\$englishnumber)                 \$english[] = \$englishnumber.' '.self::\$scale[\$i];        }        \$post = array_pop(\$english);        \$pre = implode(', ', \$english);        if (\$pre && \$post) return trim(\$pre.' and '.\$post);        return trim(\$pre.\$post);    }}  ```
Extreme example:
PHP Code:
``` for (\$i=0; \$i<20; \$i++) {    \$a = rand(0,PHP_INT_MAX);    \$b = rand(0,PHP_INT_MAX);    \$c = rand(0,PHP_INT_MAX);    \$huge = \$a.\$b.\$c;    echo(\$huge."\n".shortScale::toOrdinal(\$huge)."\n\n");}  ```
Let me know if you find a bug. If you don't like the spelling of my native English fingers, change the arrays yourself!

Edit: Bug fix already: Now supports numbers like one billion and one, and reports an error on numbers over 60 digits.

• SWEET!!!
Regardless of the fact that this thread is almost 4 years old, it saved me some real headache (and time).

I needed to build a number-word "dictionary", and with this class, I was able to bust that out in nothing flat =D
Since I needed to include the shortened versions of ordinals too, I added this method.
Hope someone else finds it useful.

PHP Code:
```     public static function toShortOrdinal(\$number) {        // Converts a number to the shortened English (alpha-numeric) ordinal. e.g. 23 to 23rd.        return \$number . substr(self::cardinalToOrdinal(self::toCardinal(\$number)),-2);    }  ```
Also, in the comment for `toOrdinal()`, it ways that it "Converts a xth format number to English. e.g. 22nd to twenty-second", but when I tested `shortScale::toOrdinal('3rd')`, it triggered the "Not a number or not a supported number type" error.
Am I missing something???

~ Mo

•

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•