[Solved] How to transform a Rust number into English words, like 1 -> “one”?


I happen to have this program on hand since it’s a common problem on “coding challenge” websites. You have to decompose the number into groups of 3 digits each and then call the function for serializing the number into text recursively. Here’s the full solution:

use std::iter::successors;

const ONES: [&str; 20] = [
    "zero",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "ten",
    "eleven",
    "twelve",
    "thirteen",
    "fourteen",
    "fifteen",
    "sixteen",
    "seventeen",
    "eighteen",
    "nineteen",
];
const TENS: [&str; 10] = [
    "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty",
    "seventy", "eighty", "ninety",
];
const ORDERS: [&str; 7] = [
    "zero",
    "thousand",
    "million",
    "billion",
    "trillion",
    "quadrillion",
    "quintillion", // enough for u64::MAX
];

pub fn encode(num: u64) -> String {
    match num {
        0..=19 => ONES[num as usize].to_string(),
        20..=99 => {
            let upper = (num / 10) as usize;
            match num % 10 {
                0 => TENS[upper].to_string(),
                lower => format!("{}-{}", TENS[upper], encode(lower)),
            }
        }
        100..=999 => format_num(num, 100, "hundred"),
        _ => {
            let (div, order) =
                successors(Some(1u64), |v| v.checked_mul(1000))
                    .zip(ORDERS.iter())
                    .find(|&(e, _)| e > num / 1000)
                    .unwrap();

            format_num(num, div, order)
        }
    }
}

fn format_num(num: u64, div: u64, order: &str) -> String {
    match (num / div, num % div) {
        (upper, 0) => format!("{} {}", encode(upper), order),
        (upper, lower) => {
            format!("{} {} {}", encode(upper), order, encode(lower))
        }
    }
}

rust playground link

0

solved How to transform a Rust number into English words, like 1 -> “one”?