Michael
Michael

Reputation: 3356

Ordinal number to words in Python

The problem

The input is a sentence containing words, numbers and ordinal numbers such as 1st, 2nd, 60th and etc.

The output should contain only words. For example:

What I have tried

num2words converts the numbers to words. But it does not work for ordinal terms such as 1st, 2nd, 60th and etc.

The question

How is possible to use python to turn ordinal numbers into words?

Upvotes: 6

Views: 4959

Answers (5)

Zachary Kosove
Zachary Kosove

Reputation: 1

def get_suffix(num: int) -> str:
  last_two_digits = num % 100
  last_digit = num % 10

  suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(last_digit, 'th')
  if last_two_digits in [11, 12, 13]: suffix = "th"
  return suffix


def ordinal_to_english(o_num: int) -> str:
  if not isinstance(o_num, int) or o_num < 0:
    return "Error: input must be a positive integer"

  # Spelling of numbers less than 20
  spelling = {
    1: "fir",
    2: "seco",
    3: "thi",
    4: "four",
    5: "fif",
    6: "six",
    7: "seven",
    8: "eigh",
    9: "nin",
    10: "ten",
    11: "eleven",
    12: "twelf",
    13: "thirteen",
    14: "fourteen",
    15: "fifteen",
    16: "sixteen",
    17: "seventeen",
    18: "eighteen",
    19: "nineteen"
  }

  # Spelling of multiples of 10
  tens_root = {
    2: "twen",
    3: "thir",
    4: "for",
    5: "fif",
    6: "six",
    7: "seven",
    8: "eigh",
    9: "ninet"
  }

  # Spelling of multiples of 100
  hundreds_spelling = {
    1: "hundred",
    2: "two hundred",
    3: "three hundred",
    4: "four hundred",
    5: "five hundred",
    6: "six hundred",
    7: "seven hundred",
    8: "eight hundred",
    9: "nine hundred"
  }

  # Get the last two digits and the last digit of the number
  last_two_digits = o_num % 100
  last_digit = o_num % 10
  tens = last_two_digits // 10
  hundreds = o_num // 100  # adjust later for larger numbers

  if last_two_digits > 19:
    root = tens_root[tens]

  if 0 < last_two_digits < 20:
    ending_ordinal = spelling[last_two_digits] + get_suffix(last_two_digits)
  elif last_two_digits == 0:
    ending_ordinal = hundreds_spelling[hundreds] + 'th'
  elif last_digit == 0:
    ending_ordinal = root + "tieth"
  else:
    ending_ordinal = spelling[last_digit] + get_suffix(last_digit)
    compound_ordinal = root + "ty-" + ending_ordinal

  if o_num < 100:
    if 0 < last_two_digits < 20 or last_digit == 0:
      return ending_ordinal
    else:
      return compound_ordinal
  else:
    if 0 < last_two_digits < 20:
      return hundreds_spelling[hundreds] + " and " + ending_ordinal
    elif last_two_digits == 0:
      return ending_ordinal
    else:
      return hundreds_spelling[hundreds] + " and " + compound_ordinal

Upvotes: 0

Michael
Michael

Reputation: 3356

The entire solution

import re
from num2words import num2words


def replace_ordinal_numbers(text):
    re_results = re.findall('(\d+(st|nd|rd|th))', text)
    for enitre_result, suffix in re_results:
        num = int(enitre_result[:-len(suffix)])
        text = text.replace(enitre_result, num2words(num, ordinal=True))
    return text


def replace_numbers(text):
    re_results = re.findall('\d+', text)
    for term in re_results:
        num = int(term)
        text = text.replace(term, num2words(num))
    return text


def convert_numbers(text):
    text = replace_ordinal_numbers(text)
    text = replace_numbers(text)

    return text


if __name__ == '__main__':
    assert convert_numbers('523rd') == 'five hundred and twenty-third'

Upvotes: 6

nimbusmom
nimbusmom

Reputation: 11

for numbers to ordinal values from 1-12, not sure how to do it the "shorter" way but this way uses basic python functions :)

def integerToOrdinal(x):
if x == 1
 ordinal = "first"
if x == 2:
    ordinal = "second"
if x == 3:
    ordinal = "third"
if x == 4:
    ordinal = "fourth"
if x == 5: 
    ordinal = "fifth"
if x == 6: 
    ordinal = "sixth"
if x == 7: 
    ordinal = "seventh"
if x == 8: 
    ordinal = "eigth"
if x == 9: 
    ordinal = "ninth"
if x == 10: 
    ordinal = "tenth"
if x == 11: 
    ordinal = "eleventh"
if x == 12: 
    ordinal = "twelfth"
return ordinal

x = int(input())
result = integerToOrdinal(x)
print(result)

Upvotes: -1

Minory
Minory

Reputation: 114

Remove the ordinal endings from the strings:

import re

re.findall('\d+', stringValue)

and then use

num2words(foundInteger, ordinal=True)

Upvotes: 5

asongtoruin
asongtoruin

Reputation: 10359

With num2words, you should be using ordinal=True to get the output you desire, as noted in its documentation:

from num2words import num2words

print(num2words(1, ordinal=True))
print(num2words(2, ordinal=True))
print(num2words(60, ordinal=True))
print(num2words(523, ordinal=True))

prints:

first
second
sixtieth
five hundred and twenty-third

Upvotes: 10

Related Questions