From 40a56c4f15390c5781265e79acb133dc3f369610 Mon Sep 17 00:00:00 2001 From: TudbuT Date: Sun, 1 Jan 2023 19:22:38 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ Cargo.toml | 9 ++++++ src/lib.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..52d11db --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "readformat" +version = "0.1.0" +edition = "2021" +repository = "https://github.com/tudbut/readformat" +license = "MIT" +description = "Very small format reader" + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d6200ba --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,83 @@ + +pub fn readf(format: &str, mut s: &str) -> Option> { + if !format.contains("{}") { + return if format == s { Some(vec![]) } else { None }; + } + if format.contains("{}{}") { + panic!("Ambiguous argument: '{}' found in format string.", "{}{}"); + } + let mut f = format; + let mut occurences = 0; + while let Some(idx) = f.find("{}") { + f = &f[(idx + 2)..]; + occurences += 1; + } + let mut result: Vec = Vec::with_capacity(occurences); + + let mut f = format; + for n in 0..=occurences { + // shave off space until next {} + let i = if let Some(x) = f.find("{}") { x } else { f.len() }; + if &f[0..i] != &s[0..i] { + return None; + } + if n == occurences { + break; + } + // abcde | a{}cd{} => bcde | cd{} + f = &f[(i + 2)..]; + s = &s[i..]; + // populate + match f.find("{}") { // has next + Some(x) => { // yes, append until next segment + // bcde | cd{} + // | \ | + // gets the next segment, and appends everything until the beginning of it + result.push(s[0..s.find(&f[0..x])?].into()); + }, + None => { // no, append until last segment + // gets the last segment (last {} until end of string) and pushes up until it + result.push(s[0..(s.len() - (format.len() - format.rfind("{}").unwrap() - 2))].into()) + }, + } + // shave the appended string away + s = &s[result[n].len()..]; + } + if result.len() != occurences { + None + } else { + Some(result) + } +} + +pub fn readf1(format: &str, s: &str) -> Option { + let r = readf(format, s); + r.map(|x| if x.len() == 0 { "".into() } else { x[0].clone() }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn t_readf1() { + assert_eq!(readf1("hello, {}", "hello, person"), Some("person".into())); + assert_eq!(readf1("hello, {}!", "hello, person!"), Some("person".into())); + assert_eq!(readf1("Hello, {}", "hello, person"), None); + assert_eq!(readf1("Hello, {}!", "hello, person"), None); + assert_eq!(readf1("hello!", "hello!"), Some("".into())); + assert_eq!(readf1("Hello!", "hello!"), None); + } + + #[test] + fn t_readf() { + assert_eq!(readf("hello, {} and {}", "hello, person 1 and person 2"), Some(vec!["person 1".into(), "person 2".into()])); + assert_eq!(readf("hello, {} and {}!", "hello, person 1 and person 2!"), Some(vec!["person 1".into(), "person 2".into()])); + assert_eq!(readf("hello, {} and {}", "hello, person"), None); + assert_eq!(readf("hello, {} and {}!", "hello, person!"), None); + assert_eq!(readf("Hello, {} and {}", "hello, person 1 and person 2"), None); + assert_eq!(readf("Hello, {} and {}!", "hello, person 1 and person 2!"), None); + assert_eq!(readf("hello!", "hello!"), Some(vec![])); + assert_eq!(readf("Hello!", "hello!"), None); + } +}