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
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 errornumber (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 errornumber 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 errorAn 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 errorA year as it is said: 1999 is "nineteen ninety-nine", 2026 is "twenty twenty-six".
number_roman(n: int) → stror an errorn in Roman numerals, from 1 to 3999: 2026 is "MMXXVI", 4 is "IV".
number_from_roman(text: str) → intor an errorThe 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.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/number_words.qwer$ curl -O https://quillolang.org/plugins/files/number_words.qweThen, in your program, all of it or only what you call:
use number_words.qweruse number_words, number_ordinal_words from number_words // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
num2words = "1.2"Example
// 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
//! 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)}Related
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.7 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.6 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.6 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.7 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.7 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.7 views · 9 downloadsThread 0 posts
On Numbers in words: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.