Update 2.0
Changes to formatting system Create a formatting struct and then pass it to the to_text macro or the to_text_fmt function to format the strings accordingly Updated docs for the new version
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/// Set the formatting of the output
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Formatting<'format> {
|
||||
/// capitalize the start of the word.
|
||||
pub capitalize: bool,
|
||||
/// Set the seperator in between digits like "threehundred,twentytwo".
|
||||
pub digit_seperator: Option<&'format str>,
|
||||
/// Set the seperator in between words like "three/hundred".
|
||||
pub place_seperator: Option<&'format str>,
|
||||
/// Set the seperator between tens place digits like "twenty-two".
|
||||
pub tens_seperator: Option<&'format str>,
|
||||
}
|
||||
|
||||
impl<'format> Formatting<'format> {
|
||||
/// Get the default formatting.
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
capitalize: true,
|
||||
digit_seperator: Some(","),
|
||||
place_seperator: Some(" "),
|
||||
tens_seperator: Some("-"),
|
||||
}
|
||||
}
|
||||
/// No formatting at all
|
||||
pub fn none() -> Self {
|
||||
Self {
|
||||
capitalize: false,
|
||||
digit_seperator: None,
|
||||
place_seperator: None,
|
||||
tens_seperator: None,
|
||||
}
|
||||
}
|
||||
/// With same formatting for all
|
||||
pub fn with_seperator(seperator: &'format str) -> Self {
|
||||
Self {
|
||||
capitalize: false,
|
||||
digit_seperator: Some(seperator),
|
||||
place_seperator: Some(seperator),
|
||||
tens_seperator: Some(seperator),
|
||||
}
|
||||
}
|
||||
/// Capitalize the formatting
|
||||
pub fn capitalize(&mut self) -> Self {
|
||||
self.capitalize = true;
|
||||
Self {
|
||||
capitalize: self.capitalize,
|
||||
digit_seperator: self.digit_seperator,
|
||||
place_seperator: self.place_seperator,
|
||||
tens_seperator: self.tens_seperator,
|
||||
}
|
||||
}
|
||||
/// Lower case the formatting struct
|
||||
pub fn decapitalize(&mut self) -> Self {
|
||||
self.capitalize = false;
|
||||
Self {
|
||||
capitalize: self.capitalize,
|
||||
digit_seperator: self.digit_seperator,
|
||||
place_seperator: self.place_seperator,
|
||||
tens_seperator: self.tens_seperator,
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-56
@@ -1,74 +1,39 @@
|
||||
//!```rust
|
||||
//!extern crate ntext;
|
||||
//!use ntext::digit_to_text;
|
||||
//!fn main() {
|
||||
//! println!("{}",digit_to_text(1).unwrap());
|
||||
//! assert_eq!("two",digit_to_text(2).unwrap());
|
||||
//! assert_ne!("five",digit_to_text(8).unwrap());
|
||||
//!}
|
||||
//!```
|
||||
//! However giving the program a zero will return an empty string.
|
||||
//!
|
||||
//! Example program with default formatting
|
||||
//!```rust
|
||||
//!extern crate ntext;
|
||||
//!use ntext::to_text;
|
||||
//!fn main() {
|
||||
//! println!("{}",to_text!(1312));
|
||||
//! assert_eq!(to_text!(1312),"onethousandthreehundredtwelve");
|
||||
//! println!("{}",to_text!(7123));
|
||||
//! assert_eq!(to_text!(7123," "),"seven thousand one hundred twenty three");
|
||||
//! assert_eq!(to_text!(7123),"Seven Thousand,One Hundred,Twenty-Three");
|
||||
//! assert_eq!(to_text!(1000),"One Thousand");
|
||||
//!}
|
||||
//!```
|
||||
//! Example program with custom formatting
|
||||
//!
|
||||
//!```rust
|
||||
//!extern crate ntext;
|
||||
//!use ntext::{Formatting,to_text};
|
||||
//!fn main() {
|
||||
//! assert_eq!(to_text!(1000, &Formatting::none().capitalize()),"OneThousand");
|
||||
//! assert_eq!(to_text!(34123, &Formatting::with_seperator("#").capitalize()),"Thirty#Four#Thousand#One#Hundred#Twenty#Three");
|
||||
//!}
|
||||
//!```
|
||||
//! This macro will also return an empty string on input zero
|
||||
//! You can also create the Formatting struct manually
|
||||
|
||||
mod no_seperator;
|
||||
mod seperator;
|
||||
mod formatting;
|
||||
mod numtext;
|
||||
mod test;
|
||||
pub use no_seperator::to_text_no_seperator;
|
||||
pub use seperator::to_text_with_seperator;
|
||||
|
||||
/// Convert digit to words in a string.
|
||||
pub fn digit_to_text(digit: u8) -> Option<String> {
|
||||
match digit {
|
||||
0 => Some("".to_string()),
|
||||
1 => Some("one".to_string()),
|
||||
2 => Some("two".to_string()),
|
||||
3 => Some("three".to_string()),
|
||||
4 => Some("four".to_string()),
|
||||
5 => Some("five".to_string()),
|
||||
6 => Some("six".to_string()),
|
||||
7 => Some("seven".to_string()),
|
||||
8 => Some("eight".to_string()),
|
||||
9 => Some("nine".to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn place_value(number: u8, place: u8, seperator: Option<&str>) -> Option<String> {
|
||||
let mut buffer = digit_to_text(number).unwrap();
|
||||
if let Some(sep) = seperator {
|
||||
if number != 0 {
|
||||
buffer.push_str(sep)
|
||||
}
|
||||
}
|
||||
match place {
|
||||
1 => (),
|
||||
2 => (), //This should never happen as 2 is included in the tens_place_holders
|
||||
3 => buffer.push_str("hundred"),
|
||||
4 => buffer.push_str("thousand"),
|
||||
5 => (), // Souldn't happen
|
||||
6 => buffer.push_str("million"),
|
||||
_ => (),
|
||||
};
|
||||
Some(buffer)
|
||||
}
|
||||
pub use formatting::Formatting;
|
||||
pub use numtext::{digit_to_text, to_text_fmt};
|
||||
|
||||
/// Macro which supports both seperator and without it
|
||||
#[macro_export]
|
||||
macro_rules! to_text {
|
||||
($number:expr) => {
|
||||
ntext::to_text_no_seperator($number);
|
||||
ntext::to_text_fmt($number, &ntext::Formatting::default());
|
||||
};
|
||||
($number:expr, $seperator:expr) => {
|
||||
ntext::to_text_with_seperator($number, $seperator);
|
||||
($number:expr, $formatting:expr) => {
|
||||
ntext::to_text_fmt($number, $formatting);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
use crate::{digit_to_text, place_value};
|
||||
fn tens_place(tens: u8, ones: u8) -> Option<String> {
|
||||
match tens {
|
||||
0 => digit_to_text(ones),
|
||||
1 => match ones {
|
||||
0 => Some("ten".to_string()),
|
||||
1 => Some("eleven".to_string()),
|
||||
2 => Some("twelve".to_string()),
|
||||
3 => Some("thirteen".to_string()),
|
||||
4 => Some("fourteen".to_string()),
|
||||
5 => Some("fifteen".to_string()),
|
||||
6 => Some("sixteen".to_string()),
|
||||
7 => Some("seventeen".to_string()),
|
||||
8 => Some("eighteen".to_string()),
|
||||
9 => Some("nineteen".to_string()),
|
||||
_ => None,
|
||||
},
|
||||
d @ 2..=5 | d @ 8 => Some({
|
||||
let mut buffer = String::new();
|
||||
match d {
|
||||
2 => buffer.push_str("twenty"),
|
||||
3 => buffer.push_str("thirty"),
|
||||
4 => buffer.push_str("forty"),
|
||||
5 => buffer.push_str("fifty"),
|
||||
8 => buffer.push_str("eighty"),
|
||||
_ => (),
|
||||
}
|
||||
buffer.push_str(digit_to_text(ones).unwrap().as_str());
|
||||
buffer
|
||||
}),
|
||||
d @ 6..=9 => Some({
|
||||
let mut string = digit_to_text(d).unwrap() + "ty";
|
||||
string.push_str(digit_to_text(ones).unwrap().as_str());
|
||||
string
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert u32 to words in a string.
|
||||
pub fn to_text_no_seperator(number: u32) -> String {
|
||||
let mut numtext: String = String::new();
|
||||
let mut last: Option<u8> = None;
|
||||
let tens_place_holders: [u8; 2] = [2, 5];
|
||||
let digits: Vec<u8> = number
|
||||
.to_string()
|
||||
.chars()
|
||||
.map(|d| d.to_digit(10).unwrap() as u8)
|
||||
.collect();
|
||||
|
||||
let mut place: u8 = digits.len() as u8;
|
||||
|
||||
for (_index, digit) in digits.iter().enumerate() {
|
||||
if tens_place_holders.contains(&place) {
|
||||
last = Some(*digit);
|
||||
place -= 1;
|
||||
continue;
|
||||
}
|
||||
if let Some(last_digit) = last {
|
||||
numtext.push_str(tens_place(last_digit, *digit).unwrap().as_str());
|
||||
if place > 2 {
|
||||
numtext.push_str(place_value(0, place, None).unwrap().as_str());
|
||||
}
|
||||
last = None;
|
||||
} else if *digit != 0 {
|
||||
numtext.push_str(place_value(*digit, place, None).unwrap().as_str())
|
||||
}
|
||||
place -= 1;
|
||||
}
|
||||
numtext
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
use crate::Formatting;
|
||||
|
||||
/// Convert digit to words in a string.
|
||||
pub fn digit_to_text(digit: u8, capitalize: bool) -> Option<String> {
|
||||
if capitalize {
|
||||
match digit {
|
||||
0 => Some("".to_string()),
|
||||
1 => Some("One".to_string()),
|
||||
2 => Some("Two".to_string()),
|
||||
3 => Some("Three".to_string()),
|
||||
4 => Some("Four".to_string()),
|
||||
5 => Some("Five".to_string()),
|
||||
6 => Some("Six".to_string()),
|
||||
7 => Some("Seven".to_string()),
|
||||
8 => Some("Eight".to_string()),
|
||||
9 => Some("Nine".to_string()),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
match digit {
|
||||
0 => Some("".to_string()),
|
||||
1 => Some("one".to_string()),
|
||||
2 => Some("two".to_string()),
|
||||
3 => Some("three".to_string()),
|
||||
4 => Some("four".to_string()),
|
||||
5 => Some("five".to_string()),
|
||||
6 => Some("six".to_string()),
|
||||
7 => Some("seven".to_string()),
|
||||
8 => Some("eight".to_string()),
|
||||
9 => Some("nine".to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
fn place_value(number: u8, place: u8, fmt: &Formatting) -> Option<String> {
|
||||
let mut buffer = digit_to_text(number, fmt.capitalize).unwrap();
|
||||
if let Some(sep) = fmt.place_seperator {
|
||||
if number != 0 && place != 1 {
|
||||
buffer.push_str(sep)
|
||||
}
|
||||
}
|
||||
if fmt.capitalize {
|
||||
match place {
|
||||
1 => (), //Can happen but should return the same digit
|
||||
2 => (), //This should never happen as 2 is included in the tens_place_holders
|
||||
3 => buffer.push_str("Hundred"),
|
||||
4 => buffer.push_str("Thousand"),
|
||||
5 => (), // Souldn't happen
|
||||
6 => buffer.push_str("Million"),
|
||||
_ => (),
|
||||
};
|
||||
} else {
|
||||
match place {
|
||||
1 => (), //Can happen but should return the same digit
|
||||
2 => (), //This should never happen as 2 is included in the tens_place_holders
|
||||
3 => buffer.push_str("hundred"),
|
||||
4 => buffer.push_str("thousand"),
|
||||
5 => (), // Souldn't happen
|
||||
6 => buffer.push_str("million"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Some(buffer)
|
||||
}
|
||||
fn tens_place(tens: u8, ones: u8, fmt: &Formatting) -> Option<String> {
|
||||
match tens {
|
||||
0 => digit_to_text(ones, fmt.capitalize),
|
||||
1 => {
|
||||
if fmt.capitalize {
|
||||
match ones {
|
||||
0 => Some("Ten".to_string()),
|
||||
1 => Some("Eleven".to_string()),
|
||||
2 => Some("Twelve".to_string()),
|
||||
3 => Some("Thirteen".to_string()),
|
||||
4 => Some("Fourteen".to_string()),
|
||||
5 => Some("Fifteen".to_string()),
|
||||
6 => Some("Sixteen".to_string()),
|
||||
7 => Some("Seventeen".to_string()),
|
||||
8 => Some("Eighteen".to_string()),
|
||||
9 => Some("Nineteen".to_string()),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
match ones {
|
||||
0 => Some("ten".to_string()),
|
||||
1 => Some("eleven".to_string()),
|
||||
2 => Some("twelve".to_string()),
|
||||
3 => Some("thirteen".to_string()),
|
||||
4 => Some("fourteen".to_string()),
|
||||
5 => Some("fifteen".to_string()),
|
||||
6 => Some("sixteen".to_string()),
|
||||
7 => Some("seventeen".to_string()),
|
||||
8 => Some("eighteen".to_string()),
|
||||
9 => Some("nineteen".to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
d @ 2..=5 | d @ 8 => Some({
|
||||
let mut buffer = String::new();
|
||||
if fmt.capitalize {
|
||||
match d {
|
||||
2 => buffer.push_str("Twenty"),
|
||||
3 => buffer.push_str("Thirty"),
|
||||
4 => buffer.push_str("Forty"),
|
||||
5 => buffer.push_str("Fifty"),
|
||||
8 => buffer.push_str("Eighty"),
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
match d {
|
||||
2 => buffer.push_str("twenty"),
|
||||
3 => buffer.push_str("thirty"),
|
||||
4 => buffer.push_str("forty"),
|
||||
5 => buffer.push_str("fifty"),
|
||||
8 => buffer.push_str("eighty"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
if let Some(sep) = fmt.tens_seperator {
|
||||
buffer.push_str(sep);
|
||||
}
|
||||
buffer.push_str(digit_to_text(ones, fmt.capitalize).unwrap().as_str());
|
||||
buffer
|
||||
}),
|
||||
d @ 6..=9 => Some({
|
||||
let mut buffer = digit_to_text(d, fmt.capitalize).unwrap() + "ty";
|
||||
if let Some(sep) = fmt.tens_seperator {
|
||||
buffer.push_str(sep);
|
||||
}
|
||||
buffer.push_str(digit_to_text(ones, fmt.capitalize).unwrap().as_str());
|
||||
buffer
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert usize to words in a string seperated by a seperator.
|
||||
pub fn to_text_fmt(number: usize, fmt: &Formatting) -> String {
|
||||
let mut numtext: String = String::new();
|
||||
let mut last: Option<u8> = None;
|
||||
let tens_place_holders: [u8; 2] = [2, 5];
|
||||
let digits: Vec<u8> = number
|
||||
.to_string()
|
||||
.chars()
|
||||
.map(|d| d.to_digit(10).unwrap() as u8)
|
||||
.collect();
|
||||
|
||||
let mut place: u8 = digits.len() as u8;
|
||||
|
||||
for (_index, digit) in digits.iter().enumerate() {
|
||||
if tens_place_holders.contains(&place) {
|
||||
last = Some(*digit);
|
||||
place -= 1;
|
||||
continue;
|
||||
}
|
||||
if *digit != 0 && place != digits.len() as u8 && numtext != "" {
|
||||
if let Some(sep) = fmt.digit_seperator {
|
||||
numtext.push_str(sep);
|
||||
}
|
||||
}
|
||||
if let Some(last_digit) = last {
|
||||
numtext.push_str(tens_place(last_digit, *digit, fmt).unwrap().as_str());
|
||||
if place > 2 {
|
||||
if let Some(sep) = fmt.digit_seperator {
|
||||
numtext.push_str(sep);
|
||||
}
|
||||
numtext.push_str(place_value(0, place, fmt).unwrap().as_str());
|
||||
}
|
||||
last = None;
|
||||
} else if *digit != 0 {
|
||||
numtext.push_str(place_value(*digit, place, fmt).unwrap().as_str());
|
||||
}
|
||||
place -= 1;
|
||||
}
|
||||
numtext
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
use crate::{digit_to_text, place_value};
|
||||
|
||||
fn tens_place_seperator(tens: u8, ones: u8, seperator: &str) -> Option<String> {
|
||||
match tens {
|
||||
0 => digit_to_text(ones),
|
||||
1 => match ones {
|
||||
0 => Some("ten".to_string()),
|
||||
1 => Some("eleven".to_string()),
|
||||
2 => Some("twelve".to_string()),
|
||||
3 => Some("thirteen".to_string()),
|
||||
4 => Some("fourteen".to_string()),
|
||||
5 => Some("fifteen".to_string()),
|
||||
6 => Some("sixteen".to_string()),
|
||||
7 => Some("seventeen".to_string()),
|
||||
8 => Some("eighteen".to_string()),
|
||||
9 => Some("nineteen".to_string()),
|
||||
_ => None,
|
||||
},
|
||||
d @ 2..=5 | d @ 8 => Some({
|
||||
let mut buffer = String::new();
|
||||
match d {
|
||||
2 => buffer.push_str("twenty"),
|
||||
3 => buffer.push_str("thirty"),
|
||||
4 => buffer.push_str("forty"),
|
||||
5 => buffer.push_str("fifty"),
|
||||
8 => buffer.push_str("eighty"),
|
||||
_ => (),
|
||||
}
|
||||
buffer.push_str(seperator);
|
||||
buffer.push_str(digit_to_text(ones).unwrap().as_str());
|
||||
buffer
|
||||
}),
|
||||
d @ 6..=9 => Some({
|
||||
let mut buffer = digit_to_text(d).unwrap() + "ty";
|
||||
buffer.push_str(seperator);
|
||||
buffer.push_str(digit_to_text(ones).unwrap().as_str());
|
||||
buffer
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert u32 to words in a string seperated by a seperator.
|
||||
pub fn to_text_with_seperator(number: u32, seperator: &str) -> String {
|
||||
let mut numtext: String = String::new();
|
||||
let mut last: Option<u8> = None;
|
||||
let tens_place_holders: [u8; 2] = [2, 5];
|
||||
let digits: Vec<u8> = number
|
||||
.to_string()
|
||||
.chars()
|
||||
.map(|d| d.to_digit(10).unwrap() as u8)
|
||||
.collect();
|
||||
|
||||
let mut place: u8 = digits.len() as u8;
|
||||
|
||||
for (_index, digit) in digits.iter().enumerate() {
|
||||
if tens_place_holders.contains(&place) {
|
||||
last = Some(*digit);
|
||||
place -= 1;
|
||||
continue;
|
||||
}
|
||||
if *digit != 0 && place != digits.len() as u8 && numtext != "" {
|
||||
numtext.push_str(seperator);
|
||||
}
|
||||
if let Some(last_digit) = last {
|
||||
numtext.push_str(
|
||||
tens_place_seperator(last_digit, *digit, seperator)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
);
|
||||
if place > 2 {
|
||||
numtext.push_str(seperator);
|
||||
numtext.push_str(place_value(0, place, Some(seperator)).unwrap().as_str());
|
||||
}
|
||||
last = None;
|
||||
} else if *digit != 0 {
|
||||
numtext.push_str(
|
||||
place_value(*digit, place, Some(seperator))
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
place -= 1;
|
||||
}
|
||||
numtext
|
||||
}
|
||||
+16
-24
@@ -3,34 +3,26 @@ mod tests {
|
||||
#[test]
|
||||
fn digits() {
|
||||
use crate::digit_to_text;
|
||||
assert_eq!(digit_to_text(9).unwrap(), "nine");
|
||||
assert_eq!(digit_to_text(3).unwrap(), "three");
|
||||
assert_eq!(digit_to_text(7).unwrap(), "seven");
|
||||
assert_eq!(digit_to_text(5).unwrap(), "five");
|
||||
assert_eq!(digit_to_text(9, false).unwrap(), "nine");
|
||||
assert_eq!(digit_to_text(3, false).unwrap(), "three");
|
||||
assert_eq!(digit_to_text(7, false).unwrap(), "seven");
|
||||
assert_eq!(digit_to_text(5, false).unwrap(), "five");
|
||||
assert_eq!(digit_to_text(5, true).unwrap(), "Five");
|
||||
}
|
||||
#[test]
|
||||
fn numbers() {
|
||||
use crate::to_text_no_seperator as to_text;
|
||||
assert_eq!(to_text(1), "one");
|
||||
assert_eq!(to_text(10), "ten");
|
||||
assert_eq!(to_text(100), "onehundred");
|
||||
assert_eq!(to_text(1000), "onethousand");
|
||||
assert_eq!(to_text(12345), "twelvethousandthreehundredfortyfive");
|
||||
assert_eq!(to_text(81123), "eightyonethousandonehundredtwentythree");
|
||||
assert_eq!(to_text(12), "twelve");
|
||||
}
|
||||
#[test]
|
||||
fn numbers_seperator() {
|
||||
use crate::to_text_with_seperator as to_text;
|
||||
assert_eq!(to_text(103, "/"), "one/hundred/three");
|
||||
assert_eq!(to_text(1000, "/"), "one/thousand");
|
||||
use crate::to_text_fmt as to_text;
|
||||
use crate::Formatting;
|
||||
let fmt = &Formatting::none();
|
||||
assert_eq!(to_text(1, fmt), "one");
|
||||
assert_eq!(to_text(10, fmt), "ten");
|
||||
assert_eq!(to_text(100, fmt), "onehundred");
|
||||
assert_eq!(to_text(1000, fmt), "onethousand");
|
||||
assert_eq!(to_text(12345, fmt), "twelvethousandthreehundredfortyfive");
|
||||
assert_eq!(
|
||||
to_text(12345, "/"),
|
||||
"twelve/thousand/three/hundred/forty/five"
|
||||
);
|
||||
assert_eq!(
|
||||
to_text(651243, "/"),
|
||||
"six/million/fifty/one/thousand/two/hundred/forty/three"
|
||||
to_text(81123, fmt),
|
||||
"eightyonethousandonehundredtwentythree"
|
||||
);
|
||||
assert_eq!(to_text(12, fmt), "twelve");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user