summaryrefslogtreecommitdiff
path: root/utils/string_proc/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-02-05 22:35:14 +0800
committer魏曹先生 <1992414357@qq.com>2026-02-05 22:35:14 +0800
commit152ce138bf7cb21d9579749afa16ee7c41c80518 (patch)
tree4d01198aa8dd557cc29bc5321d68cce031f865ec /utils/string_proc/src
parent27f6414ad1ff451feb0044af62f37dc2a6255ffa (diff)
Add documentation and examples to string processing utilities
Diffstat (limited to 'utils/string_proc/src')
-rw-r--r--utils/string_proc/src/format_path.rs78
-rw-r--r--utils/string_proc/src/format_processer.rs110
-rw-r--r--utils/string_proc/src/lib.rs46
-rw-r--r--utils/string_proc/src/macros.rs64
4 files changed, 219 insertions, 79 deletions
diff --git a/utils/string_proc/src/format_path.rs b/utils/string_proc/src/format_path.rs
index 35689b8..8750db6 100644
--- a/utils/string_proc/src/format_path.rs
+++ b/utils/string_proc/src/format_path.rs
@@ -1,6 +1,41 @@
use std::path::{Path, PathBuf};
-/// Format path str
+/// Normalize an input path string into a canonical, platform‑agnostic form.
+///
+/// This function removes ANSI escape sequences, unifies separators to `/`,
+/// collapses duplicate slashes, strips unfriendly characters (`*`, `?`, `"`, `<`, `>`, `|`),
+/// resolves simple `..` components, and preserves a trailing slash when present.
+///
+/// See examples below for the exact normalization behavior.
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::format_path::format_path_str;
+/// use std::io::Error;
+///
+/// # fn main() -> Result<(), Error> {
+/// assert_eq!(format_path_str("C:\\Users\\\\test")?, "C:/Users/test");
+/// assert_eq!(
+/// format_path_str("/path/with/*unfriendly?chars")?,
+/// "/path/with/unfriendlychars"
+/// );
+/// assert_eq!(format_path_str("\x1b[31m/path\x1b[0m")?, "/path");
+/// assert_eq!(format_path_str("/home/user/dir/")?, "/home/user/dir/");
+/// assert_eq!(
+/// format_path_str("/home/user/file.txt")?,
+/// "/home/user/file.txt"
+/// );
+/// assert_eq!(
+/// format_path_str("/home/my_user/DOCS/JVCS_TEST/Workspace/../Vault/")?,
+/// "/home/my_user/DOCS/JVCS_TEST/Vault/"
+/// );
+/// assert_eq!(format_path_str("./home/file.txt")?, "home/file.txt");
+/// assert_eq!(format_path_str("./home/path/")?, "home/path/");
+/// assert_eq!(format_path_str("./")?, "");
+/// # Ok(())
+/// # }
+/// ```
pub fn format_path_str(path: impl Into<String>) -> Result<String, std::io::Error> {
let path_str = path.into();
let ends_with_slash = path_str.ends_with('/');
@@ -73,39 +108,16 @@ fn normalize_path(path: &Path) -> PathBuf {
}
}
+/// Format a [`PathBuf`] into its canonical string form and convert it back.
+///
+/// This is a convenience wrapper around [`format_path_str`], preserving
+/// the semantics of [`PathBuf`] while applying the same normalization rules:
+/// - normalize separators to `/`
+/// - remove duplicated separators
+/// - strip ANSI escape sequences
+/// - remove unfriendly characters (`*`, `?`, etc.)
+/// - resolve simple `..` segments
pub fn format_path(path: impl Into<PathBuf>) -> Result<PathBuf, std::io::Error> {
let path_str = format_path_str(path.into().display().to_string())?;
Ok(PathBuf::from(path_str))
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_format_path() -> Result<(), std::io::Error> {
- assert_eq!(format_path_str("C:\\Users\\\\test")?, "C:/Users/test");
-
- assert_eq!(
- format_path_str("/path/with/*unfriendly?chars")?,
- "/path/with/unfriendlychars"
- );
-
- assert_eq!(format_path_str("\x1b[31m/path\x1b[0m")?, "/path");
- assert_eq!(format_path_str("/home/user/dir/")?, "/home/user/dir/");
- assert_eq!(
- format_path_str("/home/user/file.txt")?,
- "/home/user/file.txt"
- );
- assert_eq!(
- format_path_str("/home/my_user/DOCS/JVCS_TEST/Workspace/../Vault/")?,
- "/home/my_user/DOCS/JVCS_TEST/Vault/"
- );
-
- assert_eq!(format_path_str("./home/file.txt")?, "home/file.txt");
- assert_eq!(format_path_str("./home/path/")?, "home/path/");
- assert_eq!(format_path_str("./")?, "");
-
- Ok(())
- }
-}
diff --git a/utils/string_proc/src/format_processer.rs b/utils/string_proc/src/format_processer.rs
index 8d0a770..bac84c0 100644
--- a/utils/string_proc/src/format_processer.rs
+++ b/utils/string_proc/src/format_processer.rs
@@ -61,6 +61,14 @@ impl FormatProcesser {
}
/// Convert to camelCase format (brewCoffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brew_coffee");
+ /// assert_eq!(processor.to_camel_case(), "brewCoffee");
+ /// ```
pub fn to_camel_case(&self) -> String {
let mut result = String::new();
for (i, word) in self.content.iter().enumerate() {
@@ -78,6 +86,14 @@ impl FormatProcesser {
}
/// Convert to PascalCase format (BrewCoffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brew_coffee");
+ /// assert_eq!(processor.to_pascal_case(), "BrewCoffee");
+ /// ```
pub fn to_pascal_case(&self) -> String {
let mut result = String::new();
for word in &self.content {
@@ -91,21 +107,53 @@ impl FormatProcesser {
}
/// Convert to kebab-case format (brew-coffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brew_coffee");
+ /// assert_eq!(processor.to_kebab_case(), "brew-coffee");
+ /// ```
pub fn to_kebab_case(&self) -> String {
self.content.join("-").to_lowercase()
}
/// Convert to snake_case format (brew_coffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brewCoffee");
+ /// assert_eq!(processor.to_snake_case(), "brew_coffee");
+ /// ```
pub fn to_snake_case(&self) -> String {
self.content.join("_").to_lowercase()
}
/// Convert to dot.case format (brew.coffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brew_coffee");
+ /// assert_eq!(processor.to_dot_case(), "brew.coffee");
+ /// ```
pub fn to_dot_case(&self) -> String {
self.content.join(".").to_lowercase()
}
/// Convert to Title Case format (Brew Coffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brew_coffee");
+ /// assert_eq!(processor.to_title_case(), "Brew Coffee");
+ /// ```
pub fn to_title_case(&self) -> String {
let mut result = String::new();
for word in &self.content {
@@ -121,12 +169,74 @@ impl FormatProcesser {
}
/// Convert to lower case format (brew coffee)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("BREW COFFEE");
+ /// assert_eq!(processor.to_lower_case(), "brew coffee");
+ /// ```
pub fn to_lower_case(&self) -> String {
self.content.join(" ").to_lowercase()
}
/// Convert to UPPER CASE format (BREW COFFEE)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use string_proc::format_processer::FormatProcesser;
+ /// let processor = FormatProcesser::from("brew coffee");
+ /// assert_eq!(processor.to_upper_case(), "BREW COFFEE");
+ /// ```
pub fn to_upper_case(&self) -> String {
self.content.join(" ").to_uppercase()
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::format_processer::FormatProcesser;
+
+ #[test]
+ fn test_processer() {
+ let test_cases = vec![
+ ("brew_coffee", "brewCoffee"),
+ ("brew, coffee", "brewCoffee"),
+ ("brew-coffee", "brewCoffee"),
+ ("Brew.Coffee", "brewCoffee"),
+ ("bRewCofFee", "bRewCofFee"),
+ ("brewCoffee", "brewCoffee"),
+ ("b&rewCoffee", "brewCoffee"),
+ ("BrewCoffee", "brewCoffee"),
+ ("brew.coffee", "brewCoffee"),
+ ("Brew_Coffee", "brewCoffee"),
+ ("BREW COFFEE", "brewCoffee"),
+ ];
+
+ for (input, expected) in test_cases {
+ let processor = FormatProcesser::from(input);
+ assert_eq!(
+ processor.to_camel_case(),
+ expected,
+ "Failed for input: '{}'",
+ input
+ );
+ }
+ }
+
+ #[test]
+ fn test_conversions() {
+ let processor = FormatProcesser::from("brewCoffee");
+
+ assert_eq!(processor.to_upper_case(), "BREW COFFEE");
+ assert_eq!(processor.to_lower_case(), "brew coffee");
+ assert_eq!(processor.to_title_case(), "Brew Coffee");
+ assert_eq!(processor.to_dot_case(), "brew.coffee");
+ assert_eq!(processor.to_snake_case(), "brew_coffee");
+ assert_eq!(processor.to_kebab_case(), "brew-coffee");
+ assert_eq!(processor.to_pascal_case(), "BrewCoffee");
+ assert_eq!(processor.to_camel_case(), "brewCoffee");
+ }
+}
diff --git a/utils/string_proc/src/lib.rs b/utils/string_proc/src/lib.rs
index 76588c1..a5b2040 100644
--- a/utils/string_proc/src/lib.rs
+++ b/utils/string_proc/src/lib.rs
@@ -2,49 +2,3 @@ pub mod format_path;
pub mod format_processer;
pub mod macros;
pub mod simple_processer;
-
-#[cfg(test)]
-mod tests {
- use crate::format_processer::FormatProcesser;
-
- #[test]
- fn test_processer() {
- let test_cases = vec![
- ("brew_coffee", "brewCoffee"),
- ("brew, coffee", "brewCoffee"),
- ("brew-coffee", "brewCoffee"),
- ("Brew.Coffee", "brewCoffee"),
- ("bRewCofFee", "bRewCofFee"),
- ("brewCoffee", "brewCoffee"),
- ("b&rewCoffee", "brewCoffee"),
- ("BrewCoffee", "brewCoffee"),
- ("brew.coffee", "brewCoffee"),
- ("Brew_Coffee", "brewCoffee"),
- ("BREW COFFEE", "brewCoffee"),
- ];
-
- for (input, expected) in test_cases {
- let processor = FormatProcesser::from(input);
- assert_eq!(
- processor.to_camel_case(),
- expected,
- "Failed for input: '{}'",
- input
- );
- }
- }
-
- #[test]
- fn test_conversions() {
- let processor = FormatProcesser::from("brewCoffee");
-
- assert_eq!(processor.to_upper_case(), "BREW COFFEE");
- assert_eq!(processor.to_lower_case(), "brew coffee");
- assert_eq!(processor.to_title_case(), "Brew Coffee");
- assert_eq!(processor.to_dot_case(), "brew.coffee");
- assert_eq!(processor.to_snake_case(), "brew_coffee");
- assert_eq!(processor.to_kebab_case(), "brew-coffee");
- assert_eq!(processor.to_pascal_case(), "BrewCoffee");
- assert_eq!(processor.to_camel_case(), "brewCoffee");
- }
-}
diff --git a/utils/string_proc/src/macros.rs b/utils/string_proc/src/macros.rs
index 135268e..414baf0 100644
--- a/utils/string_proc/src/macros.rs
+++ b/utils/string_proc/src/macros.rs
@@ -1,3 +1,11 @@
+/// Convert to camelCase format (brewCoffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::camel_case;
+/// assert_eq!(camel_case!("brew_coffee"), "brewCoffee");
+/// ```
#[macro_export]
macro_rules! camel_case {
($input:expr) => {{
@@ -6,6 +14,14 @@ macro_rules! camel_case {
}};
}
+/// Convert to UPPER CASE format (BREW COFFEE)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::upper_case;
+/// assert_eq!(upper_case!("brew coffee"), "BREW COFFEE");
+/// ```
#[macro_export]
macro_rules! upper_case {
($input:expr) => {{
@@ -14,6 +30,14 @@ macro_rules! upper_case {
}};
}
+/// Convert to lower case format (brew coffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::lower_case;
+/// assert_eq!(lower_case!("BREW COFFEE"), "brew coffee");
+/// ```
#[macro_export]
macro_rules! lower_case {
($input:expr) => {{
@@ -22,6 +46,14 @@ macro_rules! lower_case {
}};
}
+/// Convert to Title Case format (Brew Coffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::title_case;
+/// assert_eq!(title_case!("brew_coffee"), "Brew Coffee");
+/// ```
#[macro_export]
macro_rules! title_case {
($input:expr) => {{
@@ -30,6 +62,14 @@ macro_rules! title_case {
}};
}
+/// Convert to dot.case format (brew.coffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::dot_case;
+/// assert_eq!(dot_case!("brew_coffee"), "brew.coffee");
+/// ```
#[macro_export]
macro_rules! dot_case {
($input:expr) => {{
@@ -38,6 +78,14 @@ macro_rules! dot_case {
}};
}
+/// Convert to snake_case format (brew_coffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::snake_case;
+/// assert_eq!(snake_case!("brewCoffee"), "brew_coffee");
+/// ```
#[macro_export]
macro_rules! snake_case {
($input:expr) => {{
@@ -46,6 +94,14 @@ macro_rules! snake_case {
}};
}
+/// Convert to kebab-case format (brew-coffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::kebab_case;
+/// assert_eq!(kebab_case!("brew_coffee"), "brew-coffee");
+/// ```
#[macro_export]
macro_rules! kebab_case {
($input:expr) => {{
@@ -54,6 +110,14 @@ macro_rules! kebab_case {
}};
}
+/// Convert to PascalCase format (BrewCoffee)
+///
+/// # Examples
+///
+/// ```
+/// # use string_proc::pascal_case;
+/// assert_eq!(pascal_case!("brew_coffee"), "BrewCoffee");
+/// ```
#[macro_export]
macro_rules! pascal_case {
($input:expr) => {{