Text

Numbers in words

Numbers and amounts of money in words for cheques, invoices and contracts, in English, French and Ukrainian, with ordinals, years and Roman numerals both ways.

Version 1.0.0 · 6 functions · 1 crate

#invoices#money#text#languages

Functions

What use number_words.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use number_words, number_ordinal_words from number_words (Quillo 0.6).

number_words(number: any, language: str) → stror an error

number (an int, a float, or a number as text such as "1,250.75") in words in language ("en", "fr", "fr_BE", "fr_CH", "uk"): 112 is "one hundred twelve", 42 in French "quarante-deux", 1.5 is "one point five".

number_ordinal_words(number: int, language: str) → stror an error

number as an ordinal in words: 21 is "twenty-first", in French "vingt-et-unième". Whole numbers from 0.

number_money_words(amount: any, currency: str, language: str) → stror an error

An amount of money in words, as written on a cheque: 112.5 with "USD" is "one hundred twelve dollars and fifty cents". currency is an ISO code: USD, EUR, GBP, CAD, AUD, CHF, JPY, INR, MXN and 30 more.

number_year_words(year: int, language: str) → stror an error

A year as it is said: 1999 is "nineteen ninety-nine", 2026 is "twenty twenty-six".

number_roman(n: int) → stror an error

n in Roman numerals, from 1 to 3999: 2026 is "MMXXVI", 4 is "IV".

number_from_roman(text: str) → intor an error

The number a Roman numeral stands for, case ignored: "MMXXVI" is 2026. Only the standard forms are read ("IIII" is an error).

Get it

$ quillo install number_words               # number_words.qwer into this folder$ quillo install number_words --example     # and its example, number_words.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/number_words.qwer$ curl -O https://quillolang.org/plugins/files/number_words.qwe

Then, in your program, all of it or only what you call:

main.qwe
use number_words.qweruse number_words, number_ordinal_words from number_words      // Quillo 0.6: only these

It uses this crate, which cargo fetches the first time the plugin is built:

[dependencies]
num2words = "1.2"

Example

number_words.qwe
// A cheque's amount in words, an invoice total in French, and chapter numbers in Roman numerals.////   quillo run number_words.qwe      then open http://localhost:8080/cheque?amount=1112.50use "number_words.qwer"route GET /cheque ? { amount: str, currency: str = "USD" } = { amount, words: number_money_words(amount, currency, "en")? }route GET /words = {    plain: number_words(112, "en")?,    french: number_words(1999, "fr")?,    belgian: number_words(70, "fr_BE")?,    euros: number_money_words(42.3, "EUR", "fr")?,    place: number_ordinal_words(21, "en")?,    year: number_year_words(2026, "en")?,}route GET /chapters = [1, 4, 9, 14, 2026] | map((n) => { n, roman: number_roman(n)?, back: number_from_roman(number_roman(n)?)? })
$ quillo run number_words.qwe$ curl 'localhost:8080/cheque?amount=1112.50'$ curl 'localhost:8080/words'$ curl 'localhost:8080/chapters'

Source

number_words.qwer
//! Numbers written in words, for cheques, invoices and contracts ("one hundred twelve dollars and fifty cents"), in English, French and Ukrainian, plus Roman numerals both ways.//! version: 1.0.0//!//! [dependencies]//! num2words = "1.2"use num2words::{Currency, Lang, Num2Words};fn lang(l: &str) -> Result<Lang, String> {    match l.trim() {        "" | "en" => Ok(Lang::English),        "fr" => Ok(Lang::French),        "fr_BE" | "fr-BE" => Ok(Lang::French_BE),        "fr_CH" | "fr-CH" => Ok(Lang::French_CH),        "uk" => Ok(Lang::Ukrainian),        o => Err(format!("language is \"en\", \"fr\", \"fr_BE\", \"fr_CH\" or \"uk\", not {:?}", o)),    }}fn num(n: &serde_json::Value) -> Result<Num2Words, String> {    let s = match n {        serde_json::Value::Number(x) => x.to_string(),        serde_json::Value::String(s) => s.trim().replace([',', '_', ' '], ""),        _ => return Err("a number, or a number as text".into()),    };    if s.len() > 60 {        return Err("numbers up to 60 digits".into());    }    Num2Words::parse(&s).ok_or_else(|| format!("{:?} is not a number", s))}/// `number` (an int, a float, or a number as text such as "1,250.75") in words in `language` ("en", "fr", "fr_BE", "fr_CH", "uk"): 112 is "one hundred twelve", 42 in French "quarante-deux", 1.5 is "one point five".pub fn number_words(number: serde_json::Value, language: &str) -> Result<String, String> {    num(&number)?.lang(lang(language)?).cardinal().to_words().map_err(|e| e.to_string())}/// `number` as an ordinal in words: 21 is "twenty-first", in French "vingt-et-unième". Whole numbers from 0.pub fn number_ordinal_words(number: i64, language: &str) -> Result<String, String> {    Num2Words::new(number).lang(lang(language)?).ordinal().to_words().map_err(|e| e.to_string())}/// An amount of money in words, as written on a cheque: 112.5 with "USD" is "one hundred twelve dollars and fifty cents". `currency` is an ISO code: USD, EUR, GBP, CAD, AUD, CHF, JPY, INR, MXN and 30 more.pub fn number_money_words(amount: serde_json::Value, currency: &str, language: &str) -> Result<String, String> {    let code = currency.trim().to_uppercase();    let c: Currency = if code == "USD" { Currency::DOLLAR } else { code.parse().map_err(|_| format!("no currency {:?}", currency))? };    num(&amount)?.lang(lang(language)?).currency(c).to_words().map_err(|e| e.to_string())}/// A year as it is said: 1999 is "nineteen ninety-nine", 2026 is "twenty twenty-six".pub fn number_year_words(year: i64, language: &str) -> Result<String, String> {    Num2Words::new(year).lang(lang(language)?).year().to_words().map_err(|e| e.to_string())}/// `n` in Roman numerals, from 1 to 3999: 2026 is "MMXXVI", 4 is "IV".pub fn number_roman(n: i64) -> Result<String, String> {    if !(1..=3999).contains(&n) {        return Err("Roman numerals go from 1 to 3999".into());    }    let mut n = n;    let mut out = String::new();    for (v, s) in [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")] {        while n >= v {            out.push_str(s);            n -= v;        }    }    Ok(out)}/// The number a Roman numeral stands for, case ignored: "MMXXVI" is 2026. Only the standard forms are read ("IIII" is an error).pub fn number_from_roman(text: &str) -> Result<i64, String> {    let t = text.trim().to_uppercase();    let val = |c: char| match c { 'I' => Some(1), 'V' => Some(5), 'X' => Some(10), 'L' => Some(50), 'C' => Some(100), 'D' => Some(500), 'M' => Some(1000), _ => None };    let digits: Vec<i64> = t.chars().map(|c| val(c).ok_or_else(|| format!("{:?} is not a Roman numeral", text))).collect::<Result<_, _>>()?;    if digits.is_empty() {        return Err("an empty numeral".into());    }    let mut total = 0;    for (i, &d) in digits.iter().enumerate() {        if digits.get(i + 1).map_or(false, |&next| next > d) { total -= d } else { total += d }    }    // Only the standard spelling counts: writing the number back must give the same text.    if number_roman(total).ok().as_deref() != Some(t.as_str()) {        return Err(format!("{:?} is not a standard Roman numeral", text));    }    Ok(total)}
Chinese words chinese_segment.qwer · 1.0.0Chinese text split into words for search indexes and counts, with parts of speech, and written in pinyin with tones, tone numbers or initials for sorting and finding names.chinesesearchtextlanguages7 views · 7 downloadsHyphenation hyphenation.qwer · 1.0.0Words hyphenated by the rules of 80 languages and spellings, patterns built in: a word's syllables, soft hyphens put in text and HTML for narrow columns and e-mails, and text wrapped at a width with words broken where they may be.textlanguagesemailwriting6 views · 7 downloadsJapanese kana kana.qwer · 1.0.0Japanese kana: romaji typed as hiragana or katakana, kana written in Hepburn romaji, hiragana and katakana each to the other, half-width katakana from bank and till systems made full-width, and which scripts a text uses.unicodelanguagesformstext6 views · 10 downloadsSentences sentences.qwer · 1.0.0Text split into sentences as a reader would: "Dr.", "p.m.", initials, decimals, "e.g." and quoted questions handled, with abbreviations for seven languages; positions for highlighting, and previews of whole sentences that fit a length.textwritingseolanguages7 views · 9 downloadsStemming stemming.qwer · 1.0.0Words cut to their stems in 18 languages, so running, runs and run count as one word in a search or a tag cloud.searchtextlanguagestags7 views · 8 downloadsStop words stopwords.qwer · 1.0.0Stop words of 58 languages (the, and, of; le, et, de), and text with them taken out, for search queries, keywords and tag clouds.searchtextlanguageskeywords7 views · 9 downloads
Thread
87Useful? Like it, or add to its thread below.

Thread 0 posts

On Numbers in words: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.