Skip to main content

sal_text/
fix.rs

1pub fn name_fix(text: &str) -> String {
2    let mut result = String::with_capacity(text.len());
3
4    let mut last_was_underscore = false;
5    for c in text.chars() {
6        // Keep only ASCII characters
7        if c.is_ascii() {
8            // Replace specific characters with underscore
9            if c.is_whitespace()
10                || c == ','
11                || c == '-'
12                || c == '"'
13                || c == '\''
14                || c == '#'
15                || c == '!'
16                || c == '('
17                || c == ')'
18                || c == '['
19                || c == ']'
20                || c == '='
21                || c == '+'
22                || c == '<'
23                || c == '>'
24                || c == '@'
25                || c == '$'
26                || c == '%'
27                || c == '^'
28                || c == '&'
29                || c == '*'
30            {
31                // Only add underscore if the last character wasn't an underscore
32                if !last_was_underscore {
33                    result.push('_');
34                    last_was_underscore = true;
35                }
36            } else {
37                // Add the character as is (will be converted to lowercase later)
38                result.push(c);
39                last_was_underscore = false;
40            }
41        }
42        // Non-ASCII characters are simply skipped
43    }
44
45    // Convert to lowercase
46    return result.to_lowercase();
47}
48
49pub fn path_fix(text: &str) -> String {
50    // If path ends with '/', return as is
51    if text.ends_with('/') {
52        return text.to_string();
53    }
54
55    // Find the last '/' to extract the filename part
56    match text.rfind('/') {
57        Some(pos) => {
58            // Extract the path and filename parts
59            let path = &text[..=pos];
60            let filename = &text[pos + 1..];
61
62            // Apply name_fix to the filename part only
63            return format!("{}{}", path, name_fix(filename));
64        }
65        None => {
66            // No '/' found, so the entire text is a filename
67            return name_fix(text);
68        }
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_name_fix() {
78        // Test ASCII conversion and special character replacement
79        assert_eq!(name_fix("Hello World"), "hello_world");
80        assert_eq!(name_fix("File-Name.txt"), "file_name.txt");
81        assert_eq!(name_fix("Test!@#$%^&*()"), "test_");
82        assert_eq!(name_fix("Space, Tab\t, Comma,"), "space_tab_comma_");
83        assert_eq!(name_fix("Quotes\"'"), "quotes_");
84        assert_eq!(name_fix("Brackets[]<>"), "brackets_");
85        assert_eq!(name_fix("Operators=+-"), "operators_");
86
87        // Test non-ASCII characters removal
88        assert_eq!(name_fix("Café"), "caf");
89        assert_eq!(name_fix("Résumé"), "rsum");
90        assert_eq!(name_fix("Über"), "ber");
91
92        // Test lowercase conversion
93        assert_eq!(name_fix("UPPERCASE"), "uppercase");
94        assert_eq!(name_fix("MixedCase"), "mixedcase");
95    }
96
97    #[test]
98    fn test_path_fix() {
99        // Test path ending with /
100        assert_eq!(path_fix("/path/to/directory/"), "/path/to/directory/");
101
102        // Test single filename
103        assert_eq!(path_fix("filename.txt"), "filename.txt");
104        assert_eq!(path_fix("UPPER-file.md"), "upper_file.md");
105
106        // Test path with filename
107        assert_eq!(path_fix("/path/to/File Name.txt"), "/path/to/file_name.txt");
108        assert_eq!(
109            path_fix("./relative/path/to/DOCUMENT-123.pdf"),
110            "./relative/path/to/document_123.pdf"
111        );
112        assert_eq!(
113            path_fix("/absolute/path/to/Résumé.doc"),
114            "/absolute/path/to/rsum.doc"
115        );
116
117        // Test path with special characters in filename
118        assert_eq!(
119            path_fix("/path/with/[special]<chars>.txt"),
120            "/path/with/_special_chars_.txt"
121        );
122    }
123}