├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── NOTICE ├── README.md └── src ├── format.rs ├── languages.rs ├── languages └── en_us.rs ├── lib.rs └── tests.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | - develop 9 | 10 | env: 11 | CARGO_TERM_COLOR: always 12 | CODECOV_TOKEN: ${{ secrets.CODECOV }} 13 | 14 | jobs: 15 | test: 16 | 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | rust: 21 | - stable 22 | - beta 23 | - nightly 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | - uses: actions-rs/toolchain@v1 28 | with: 29 | profile: minimal 30 | toolchain: ${{ matrix.rust }} 31 | override: true 32 | components: rustfmt, clippy 33 | 34 | - name: Build 35 | run: cargo build --verbose 36 | 37 | - name: Test 38 | run: cargo test --verbose 39 | 40 | - name: Format 41 | uses: actions-rs/cargo@v1 42 | with: 43 | command: fmt 44 | args: --all -- --check 45 | 46 | - name: Lint 47 | uses: actions-rs/cargo@v1 48 | with: 49 | command: clippy 50 | args: -- -D warnings 51 | 52 | coverage: 53 | needs: test 54 | runs-on: ubuntu-latest 55 | steps: 56 | - uses: actions/checkout@v2 57 | - name: Generate coverage file 58 | run: | 59 | cargo install cargo-tarpaulin --vers "^0.13" 60 | cargo tarpaulin --out Xml --verbose 61 | - name: Upload to Codecov 62 | uses: codecov/codecov-action@v1 63 | with: 64 | file: cobertura.xml 65 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - 'v*' 5 | 6 | name: Create Release 7 | 8 | jobs: 9 | create-github-release: 10 | name: Create GitHub Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | - name: Create Release Notes 16 | uses: actions/github-script@v4.0.2 17 | with: 18 | github-token: ${{secrets.GITHUB_TOKEN}} 19 | script: | 20 | await github.request(`POST /repos/${{ github.repository }}/releases`, { 21 | tag_name: "${{ github.ref }}", 22 | generate_release_notes: true 23 | }); 24 | 25 | publish-crate: 26 | name: Publish to crates.io 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v1 30 | - uses: actions-rs/toolchain@v1 31 | with: 32 | profile: minimal 33 | toolchain: stable 34 | - run: cargo login ${CRATES_IO_TOKEN} 35 | env: 36 | CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} 37 | - name: publish 38 | run: cargo publish 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | 4 | .idea -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.2.0] 2021-10-15 8 | ### Changed 9 | - [**BREAKING API CHANGE**]: Removed the `NumberNames` struct; calls for names are now into simple functions 10 | - Rebuilt the algorithm for generating cardinal names 11 | - Moved name generating algorithms into specific `en_us` module to make room for future language additions 12 | 13 | ### Added 14 | - `Language` enum to specify the language desired for the given number name 15 | - `Format` struct, currently only configures the language 16 | 17 | ## [0.1.2] 2021-10-05 18 | ### Fixed 19 | - Changed license identifier to be picked up correctly by crates.io 20 | 21 | ## [0.1.1] 2021-10-05 22 | ### Added 23 | - Codecov build script 24 | - Separate changelog (this file) 25 | ### Changed 26 | - String concatenation style for ordinal numbers 27 | 28 | ## [0.1.0] 2021-09-24 29 | ### Added 30 | - positive cardinal formatting up to `u64::MAX()` in en_US 31 | - positive ordinal formatting up to `u64::MAX()` in en_US 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Number Names 2 | 3 | [TBD] -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "number-names" 3 | version = "0.2.0" 4 | edition = "2018" 5 | description = "Number names is a Rust library to provide formatted string names for cardinal and ordinal numbers." 6 | authors = [ 7 | "Robert M Chambers " 8 | ] 9 | readme = "README.md" 10 | license = "Apache-2.0" 11 | repository = "https://github.com/calteran/number_names_rs/" 12 | documentation = "https://docs.rs/number-names/" 13 | 14 | 15 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 16 | 17 | [lib] 18 | doctest = false 19 | 20 | 21 | [dependencies] 22 | 23 | [dev-dependencies] 24 | rstest = "0.11.0" 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Number Names 2 | Copyright 2021 Robert M Chambers 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | --- 17 | 18 | The algorithm for cardinal names was sourced from https://stackoverflow.com/a/61604407/2313245 19 | and is used under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License. 20 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Number Names 2 | Copyright 2021 Robert M Chambers 3 | 4 | This project was initially developed by Robert M Chambers for the Rust community. 5 | 6 | The algorithm for cardinal names was provided by @pretzelhammer on StackOverflow 7 | (https://stackoverflow.com/a/61604407/2313245) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Number Names 2 | 3 | [![build](https://github.com/calteran/number_names_rs/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/calteran/number_names_rs/actions/workflows/build.yml) 4 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 5 | [![codecov](https://codecov.io/gh/calteran/number_names_rs/branch/main/graph/badge.svg?token=WVBHQ5O0MX)](https://codecov.io/gh/calteran/number_names_rs) 6 | [![crates.io](https://img.shields.io/crates/v/number-names)](https://img.shields.io/crates/v/number-names) 7 | 8 | Number names is a Rust library to provide formatted string names for cardinal and ordinal numbers. 9 | 10 | *At this time, only American English is supported, but there are future plans for i18n.* 11 | 12 | ## Example usage: 13 | 14 | ```rust 15 | assert_eq!(number_names::cardinal(10), "ten"); 16 | assert_eq!(number_names::ordinal(10), "tenth"); 17 | ``` 18 | 19 | See full documentation at [https://docs.rs/number-names/](https://docs.rs/number-names/). 20 | 21 | ## Contributing 22 | 23 | As this is my first project in Rust, I'm sure there are significant improvements to be made in both the algorithms 24 | and implementation. I will gladly accept any constructive criticisms, suggestions or pull requests that make 25 | this small project more efficient or accurate. 26 | 27 | More specific needs include expanding the library to more languages. To add a language, create a file in the 28 | /languages folder with the [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag) for the language, 29 | in snake_case. Implement the `cardinal_with_format` and `ordinal_with_format` public functions, returning `String`s 30 | for each `u64` number. Add a tests module (either separately or in the same file) with tests covering several generic 31 | as well as specific edge-cases for the language. Add an option to the `number_names::languages::Language` enum with 32 | the IETF tag in CamelCase. Send me a pull request with the completed changes once all your tests are passing! 33 | 34 | ## Roadmap 35 | 36 | With the release of version 0.2.0 that saw significant refactoring to make the library more extensible for both 37 | formatting and languages, my hope is that the API is now relatively stable. I hope developers will open issues 38 | or submit enhancements to help strengthen these foundations. I will continue to maintain this library and intend to 39 | promote the most current version to 1.0 to signify stability no sooner than 6 months after the most recent 40 | breaking change. 41 | -------------------------------------------------------------------------------- /src/format.rs: -------------------------------------------------------------------------------- 1 | //! Defines configuration struct Format to control number name formatting. 2 | use crate::languages::Language; 3 | use crate::languages::Language::EnUs; 4 | 5 | /// 6 | /// Configuration struct to control formatting of the number names. 7 | /// Currently used only to specify the language. 8 | /// 9 | /// Examples: 10 | /// 11 | /// ```rust 12 | /// // default format 13 | /// let fmt = number_names::Format::default(); 14 | /// 15 | /// // specify a language 16 | /// let fmt = number_names::Format(number_names::languages::Language::EnUs); 17 | /// ``` 18 | pub struct Format { 19 | /// Language the number name should be formatted in 20 | pub language: Language, 21 | } 22 | 23 | impl Format { 24 | /// Return a Format with the default values 25 | /// (currently only language set to American English) 26 | /// 27 | /// Example: 28 | /// ```rust 29 | /// let fmt = number_names::Format::default(); 30 | /// assert_eq!(fmt, number_names::Format{number_names::languages::Language::EnUs}); 31 | /// ``` 32 | pub fn default() -> Format { 33 | Format { language: EnUs } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/languages.rs: -------------------------------------------------------------------------------- 1 | //! Defines an enum to specify available languages from this library 2 | 3 | /// List of the available languages provided by this library. 4 | pub enum Language { 5 | /// English (generic) 6 | En, 7 | /// American English 8 | EnUs, 9 | } 10 | 11 | pub mod en_us; 12 | -------------------------------------------------------------------------------- /src/languages/en_us.rs: -------------------------------------------------------------------------------- 1 | //! Generate number names in American English 2 | use crate::format::Format; 3 | use std::cmp; 4 | 5 | /// Return cardinal number name for a given number with a given format in American English 6 | /// 7 | /// Example: 8 | /// ```rust 9 | /// use number_names::{languages::en_us::cardinal_with_fmt, Format}; 10 | /// 11 | /// assert_eq(cardinal_with_fmt(20, Format::default()), "twenty".to_string()); 12 | /// ``` 13 | pub fn cardinal_with_format(num: u64, fmt: Format) -> String { 14 | encode(num, fmt) 15 | } 16 | 17 | /// Return cardinal number name for a given number with a given format in American English 18 | /// 19 | /// Example: 20 | /// ```rust 21 | /// use number_names::{languages::en_us::ordinal_with_fmt, Format}; 22 | /// 23 | /// assert_eq(ordinal_with_fmt(20, Format::default()), "twentieth".to_string()); 24 | /// ``` 25 | pub fn ordinal_with_format(num: u64, fmt: Format) -> String { 26 | // Lets start with the cardinal version and then replace the last word 27 | let cardinal = cardinal_with_format(num, fmt); 28 | 29 | // find the character (this is all in ASCII!) before the last word 30 | // it might be a space or a dash (eg. "thirty-three") 31 | let last_break = match (cardinal.rfind(' '), cardinal.rfind('-')) { 32 | (Some(space), Some(dash)) => cmp::max(space, dash) + 1, 33 | (Some(space), None) => space + 1, 34 | (None, Some(dash)) => dash + 1, 35 | (None, None) => 0, 36 | }; 37 | 38 | // Most numbers just add "-th" to the end of the cardinal name, but others are special 39 | match NOT_TH 40 | .iter() 41 | .position(|(word, _)| word.eq(&&cardinal[last_break..])) 42 | { 43 | Some(index) => String::from(&cardinal[..last_break]) + NOT_TH[index].1, 44 | None => cardinal + "th", 45 | } 46 | } 47 | 48 | fn encode(num: u64, fmt: Format) -> String { 49 | let mut num = num; 50 | if num > 0 { 51 | std::iter::from_fn(|| { 52 | if num > 0 { 53 | let v = num % 1000; 54 | num /= 1000; 55 | Some(v) 56 | } else { 57 | None 58 | } 59 | }) 60 | .map(|num| format_num(num, &fmt)) 61 | .zip(ORDERS.iter()) 62 | .filter(|(num, _)| num != "zero") 63 | .map(|(num, order)| num + order) 64 | .collect::>() 65 | .into_iter() 66 | .rev() 67 | .collect::>() 68 | .join(" ") 69 | } else { 70 | "zero".to_string() 71 | } 72 | } 73 | 74 | fn format_num(num: u64, fmt: &Format) -> String { 75 | match num { 76 | 0..=19 => ONES[num as usize].to_string(), 77 | 20..=99 => { 78 | let upper = (num / 10) as usize; 79 | match num % 10 { 80 | 0 => TENS[upper].to_string(), 81 | lower => format!("{}-{}", TENS[upper], ONES[lower as usize]), 82 | } 83 | } 84 | _ => { 85 | let mut v = vec![ 86 | format_num(num / 100, fmt), 87 | "hundred".to_string(), 88 | format_num(num % 100, fmt), 89 | ]; 90 | v.retain(|s| s != "zero"); 91 | v.join(" ") 92 | } 93 | } 94 | } 95 | 96 | const ONES: [&str; 20] = [ 97 | "zero", 98 | "one", 99 | "two", 100 | "three", 101 | "four", 102 | "five", 103 | "six", 104 | "seven", 105 | "eight", 106 | "nine", 107 | "ten", 108 | "eleven", 109 | "twelve", 110 | "thirteen", 111 | "fourteen", 112 | "fifteen", 113 | "sixteen", 114 | "seventeen", 115 | "eighteen", 116 | "nineteen", 117 | ]; 118 | 119 | const TENS: [&str; 10] = [ 120 | "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", 121 | ]; 122 | 123 | const ORDERS: [&str; 7] = [ 124 | "", 125 | " thousand", 126 | " million", 127 | " billion", 128 | " trillion", 129 | " quadrillion", 130 | " quintillion", 131 | ]; 132 | 133 | const NOT_TH: [(&str, &str); 15] = [ 134 | ("one", "first"), 135 | ("two", "second"), 136 | ("three", "third"), 137 | ("five", "fifth"), 138 | ("eight", "eighth"), 139 | ("nine", "ninth"), 140 | ("twelve", "twelfth"), 141 | ("twenty", "twentieth"), 142 | ("thirty", "thirtieth"), 143 | ("forty", "fortieth"), 144 | ("fifty", "fiftieth"), 145 | ("sixty", "sixtieth"), 146 | ("seventy", "seventieth"), 147 | ("eighty", "eightieth"), 148 | ("ninety", "ninetieth"), 149 | ]; 150 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(missing_docs)] 2 | #![warn(rustdoc::missing_doc_code_examples)] 3 | #![doc = include_str!("../README.md")] 4 | 5 | pub mod format; 6 | pub mod languages; 7 | 8 | use crate::format::Format; 9 | use crate::languages::Language::*; 10 | 11 | /// Return cardinal number name for a given number with the default format 12 | /// 13 | /// Example: 14 | /// ```rust 15 | /// assert_eq!(number_names::cardinal(10), "ten".to_string()) 16 | /// ``` 17 | pub fn cardinal(num: u64) -> String { 18 | cardinal_with_fmt(num, Format::default()) 19 | } 20 | 21 | /// Return cardinal number name for a given number with a given format 22 | /// 23 | /// Example: 24 | /// ```rust 25 | /// use number_names::{cardinal_with_fmt, Format}; 26 | /// 27 | /// assert_eq(cardinal_with_fmt(20, Format::default()), "twenty".to_string()); 28 | /// ``` 29 | pub fn cardinal_with_fmt(num: u64, fmt: Format) -> String { 30 | match fmt.language { 31 | EnUs => crate::languages::en_us::cardinal_with_format(num, fmt), 32 | _ => crate::languages::en_us::cardinal_with_format(num, fmt), 33 | } 34 | } 35 | 36 | /// Return ordinal number name for a given number with the default format 37 | /// 38 | /// Example: 39 | /// ```rust 40 | /// assert_eq!(number_names::ordinal(10), "tenth".to_string()) 41 | /// ``` 42 | pub fn ordinal(num: u64) -> String { 43 | ordinal_with_fmt(num, Format::default()) 44 | } 45 | 46 | /// Return ordinal number name for a given number with a given format 47 | /// 48 | /// Example: 49 | /// ```rust 50 | /// use number_names::{ordinal_with_fmt, Format}; 51 | /// 52 | /// assert_eq(ordinal_with_fmt(20, Format::default()), "twentieth".to_string()); 53 | /// ``` 54 | pub fn ordinal_with_fmt(num: u64, fmt: Format) -> String { 55 | match fmt.language { 56 | EnUs => crate::languages::en_us::ordinal_with_format(num, fmt), 57 | _ => crate::languages::en_us::ordinal_with_format(num, fmt), 58 | } 59 | } 60 | 61 | mod tests; 62 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use crate::*; 4 | use rstest::rstest; 5 | 6 | #[rstest] 7 | #[case(0, "zero")] 8 | #[case(1, "one")] 9 | #[case(2, "two")] 10 | #[case(3, "three")] 11 | #[case(4, "four")] 12 | #[case(5, "five")] 13 | #[case(6, "six")] 14 | #[case(7, "seven")] 15 | #[case(8, "eight")] 16 | #[case(9, "nine")] 17 | #[case(10, "ten")] 18 | #[case(11, "eleven")] 19 | #[case(12, "twelve")] 20 | #[case(13, "thirteen")] 21 | #[case(14, "fourteen")] 22 | #[case(15, "fifteen")] 23 | #[case(16, "sixteen")] 24 | #[case(17, "seventeen")] 25 | #[case(18, "eighteen")] 26 | #[case(19, "nineteen")] 27 | #[case(20, "twenty")] 28 | #[case(30, "thirty")] 29 | #[case(34, "thirty-four")] 30 | #[case(40, "forty")] 31 | #[case(50, "fifty")] 32 | #[case(60, "sixty")] 33 | #[case(70, "seventy")] 34 | #[case(80, "eighty")] 35 | #[case(90, "ninety")] 36 | #[case(100, "one hundred")] 37 | #[case(567, "five hundred sixty-seven")] 38 | #[case(8_910, "eight thousand nine hundred ten")] 39 | #[case(11_121, "eleven thousand one hundred twenty-one")] 40 | #[case(314_151, "three hundred fourteen thousand one hundred fifty-one")] 41 | #[case( 42 | 6_171_819, 43 | "six million one hundred seventy-one thousand eight hundred nineteen" 44 | )] 45 | #[case( 46 | 20_212_223, 47 | "twenty million two hundred twelve thousand two hundred twenty-three" 48 | )] 49 | #[case( 50 | 242_526_272, 51 | "two hundred forty-two million five hundred twenty-six thousand two hundred seventy-two" 52 | )] 53 | #[case(8_293_031_323, "eight billion two hundred ninety-three million thirty-one thousand three hundred twenty-three")] 54 | #[case(33_435_363_738, "thirty-three billion four hundred thirty-five million three hundred sixty-three thousand seven hundred thirty-eight")] 55 | #[case(394_041_424_344, "three hundred ninety-four billion forty-one million four hundred twenty-four thousand three hundred forty-four")] 56 | #[case(4_546_474_849_505, "four trillion five hundred forty-six billion four hundred seventy-four million eight hundred forty-nine thousand five hundred five")] 57 | #[case(15_253_545_556_575, "fifteen trillion two hundred fifty-three billion five hundred forty-five million five hundred fifty-six thousand five hundred seventy-five")] 58 | #[case(859_606_162_636_465, "eight hundred fifty-nine trillion six hundred six billion one hundred sixty-two million six hundred thirty-six thousand four hundred sixty-five")] 59 | #[case(6_667_686_970_717_273, "six quadrillion six hundred sixty-seven trillion six hundred eighty-six billion nine hundred seventy million seven hundred seventeen thousand two hundred seventy-three")] 60 | #[case(74_757_677_787_980_818, "seventy-four quadrillion seven hundred fifty-seven trillion six hundred seventy-seven billion seven hundred eighty-seven million nine hundred eighty thousand eight hundred eighteen")] 61 | #[case(283_848_586_878_889_909, "two hundred eighty-three quadrillion eight hundred forty-eight trillion five hundred eighty-six billion eight hundred seventy-eight million eight hundred eighty-nine thousand nine hundred nine")] 62 | #[case(1_929_394_959_697_989_910, "one quintillion nine hundred twenty-nine quadrillion three hundred ninety-four trillion nine hundred fifty-nine billion six hundred ninety-seven million nine hundred eighty-nine thousand nine hundred ten")] 63 | #[case(18_446_744_073_709_551_615, "eighteen quintillion four hundred forty-six quadrillion seven hundred forty-four trillion seventy-three billion seven hundred nine million five hundred fifty-one thousand six hundred fifteen")] 64 | #[case(1_000_000_000, "one billion")] 65 | fn cardinal_name(#[case] input: u64, #[case] expected: String) { 66 | assert_eq!(expected, cardinal(input)) 67 | } 68 | 69 | #[test] 70 | fn ordinal_name() { 71 | let values = values(); 72 | 73 | for value in values { 74 | assert_eq!( 75 | value.2.to_string(), 76 | ordinal(value.0), 77 | "Failed on {}", 78 | value.0 79 | ); 80 | } 81 | } 82 | 83 | fn values() -> [(u64, &'static str, &'static str); 49] { 84 | [ 85 | (0, 86 | "zero", 87 | "zeroth"), 88 | (1, 89 | "one", 90 | "first"), 91 | (2, 92 | "two", 93 | "second"), 94 | (3, 95 | "three", 96 | "third"), 97 | (4, 98 | "four", 99 | "fourth"), 100 | (5, 101 | "five", 102 | "fifth"), 103 | (6, 104 | "six", 105 | "sixth"), 106 | (7, 107 | "seven", 108 | "seventh"), 109 | (8, 110 | "eight", 111 | "eighth"), 112 | (9, 113 | "nine", 114 | "ninth"), 115 | (10, 116 | "ten", 117 | "tenth"), 118 | (11, 119 | "eleven", 120 | "eleventh"), 121 | (12, 122 | "twelve", 123 | "twelfth"), 124 | (13, 125 | "thirteen", 126 | "thirteenth"), 127 | (14, 128 | "fourteen", 129 | "fourteenth"), 130 | (15, 131 | "fifteen", 132 | "fifteenth"), 133 | (16, 134 | "sixteen", 135 | "sixteenth"), 136 | (17, 137 | "seventeen", 138 | "seventeenth"), 139 | (18, 140 | "eighteen", 141 | "eighteenth"), 142 | (19, 143 | "nineteen", 144 | "nineteenth"), 145 | (20, 146 | "twenty", 147 | "twentieth"), 148 | (30, 149 | "thirty", 150 | "thirtieth"), 151 | (34, 152 | "thirty-four", 153 | "thirty-fourth"), 154 | (40, 155 | "forty", 156 | "fortieth"), 157 | (50, 158 | "fifty", 159 | "fiftieth"), 160 | (60, 161 | "sixty", 162 | "sixtieth"), 163 | (70, 164 | "seventy", 165 | "seventieth"), 166 | (80, 167 | "eighty", 168 | "eightieth"), 169 | (90, 170 | "ninety", 171 | "ninetieth"), 172 | (100, 173 | "one hundred", 174 | "one hundredth"), 175 | (567, 176 | "five hundred sixty-seven", 177 | "five hundred sixty-seventh"), 178 | (8_910, 179 | "eight thousand nine hundred ten", 180 | "eight thousand nine hundred tenth"), 181 | (11_121, 182 | "eleven thousand one hundred twenty-one", 183 | "eleven thousand one hundred twenty-first"), 184 | (314_151, 185 | "three hundred fourteen thousand one hundred fifty-one", 186 | "three hundred fourteen thousand one hundred fifty-first"), 187 | (6_171_819, 188 | "six million one hundred seventy-one thousand eight hundred nineteen", 189 | "six million one hundred seventy-one thousand eight hundred nineteenth"), 190 | (20_212_223, 191 | "twenty million two hundred twelve thousand two hundred twenty-three", 192 | "twenty million two hundred twelve thousand two hundred twenty-third"), 193 | (242_526_272, 194 | "two hundred forty-two million five hundred twenty-six thousand two hundred seventy-two", 195 | "two hundred forty-two million five hundred twenty-six thousand two hundred seventy-second"), 196 | (8_293_031_323, 197 | "eight billion two hundred ninety-three million thirty-one thousand three hundred twenty-three", 198 | "eight billion two hundred ninety-three million thirty-one thousand three hundred twenty-third"), 199 | (33_435_363_738, 200 | "thirty-three billion four hundred thirty-five million three hundred sixty-three thousand seven hundred thirty-eight", 201 | "thirty-three billion four hundred thirty-five million three hundred sixty-three thousand seven hundred thirty-eighth"), 202 | (394_041_424_344, 203 | "three hundred ninety-four billion forty-one million four hundred twenty-four thousand three hundred forty-four", 204 | "three hundred ninety-four billion forty-one million four hundred twenty-four thousand three hundred forty-fourth"), 205 | (4_546_474_849_505, 206 | "four trillion five hundred forty-six billion four hundred seventy-four million eight hundred forty-nine thousand five hundred five", 207 | "four trillion five hundred forty-six billion four hundred seventy-four million eight hundred forty-nine thousand five hundred fifth"), 208 | (15_253_545_556_575, 209 | "fifteen trillion two hundred fifty-three billion five hundred forty-five million five hundred fifty-six thousand five hundred seventy-five", 210 | "fifteen trillion two hundred fifty-three billion five hundred forty-five million five hundred fifty-six thousand five hundred seventy-fifth"), 211 | (859_606_162_636_465, 212 | "eight hundred fifty-nine trillion six hundred six billion one hundred sixty-two million six hundred thirty-six thousand four hundred sixty-five", 213 | "eight hundred fifty-nine trillion six hundred six billion one hundred sixty-two million six hundred thirty-six thousand four hundred sixty-fifth"), 214 | (6_667_686_970_717_273, 215 | "six quadrillion six hundred sixty-seven trillion six hundred eighty-six billion nine hundred seventy million seven hundred seventeen thousand two hundred seventy-three", 216 | "six quadrillion six hundred sixty-seven trillion six hundred eighty-six billion nine hundred seventy million seven hundred seventeen thousand two hundred seventy-third"), 217 | (74_757_677_787_980_818, 218 | "seventy-four quadrillion seven hundred fifty-seven trillion six hundred seventy-seven billion seven hundred eighty-seven million nine hundred eighty thousand eight hundred eighteen", 219 | "seventy-four quadrillion seven hundred fifty-seven trillion six hundred seventy-seven billion seven hundred eighty-seven million nine hundred eighty thousand eight hundred eighteenth"), 220 | (283_848_586_878_889_909, 221 | "two hundred eighty-three quadrillion eight hundred forty-eight trillion five hundred eighty-six billion eight hundred seventy-eight million eight hundred eighty-nine thousand nine hundred nine", 222 | "two hundred eighty-three quadrillion eight hundred forty-eight trillion five hundred eighty-six billion eight hundred seventy-eight million eight hundred eighty-nine thousand nine hundred ninth"), 223 | (1_929_394_959_697_989_910, 224 | "one quintillion nine hundred twenty-nine quadrillion three hundred ninety-four trillion nine hundred fifty-nine billion six hundred ninety-seven million nine hundred eighty-nine thousand nine hundred ten", 225 | "one quintillion nine hundred twenty-nine quadrillion three hundred ninety-four trillion nine hundred fifty-nine billion six hundred ninety-seven million nine hundred eighty-nine thousand nine hundred tenth"), 226 | (18_446_744_073_709_551_615, 227 | "eighteen quintillion four hundred forty-six quadrillion seven hundred forty-four trillion seventy-three billion seven hundred nine million five hundred fifty-one thousand six hundred fifteen", 228 | "eighteen quintillion four hundred forty-six quadrillion seven hundred forty-four trillion seventy-three billion seven hundred nine million five hundred fifty-one thousand six hundred fifteenth"), 229 | (1_000_000_000, 230 | "one billion", 231 | "one billionth") 232 | ] 233 | } 234 | } 235 | --------------------------------------------------------------------------------