lano_stre/lib.rs
1// pub fn add(left: u64, right: u64) -> u64 {
2// left + right
3// }
4
5// #[cfg(test)]
6// mod tests {
7// use super::*;
8
9// #[test]
10// fn it_works() {
11// let result = add(2, 2);
12// assert_eq!(result, 4);
13// }
14// }
15
16use regex::Regex;
17// use fancy_regex::Regex;
18
19/// mock js String.prototype.replace
20///
21/// ```rs
22/// let result = str_pattern_replace(input_string, pattern, replacement_function);
23/// ```
24fn str_pattern_replace<F>(input: &str, pattern: &str, replacement: F) -> String
25where
26 F: Fn(usize, &str) -> String,
27{
28 // Compile the regex pattern
29 let regex = Regex::new(pattern).expect("Invalid regex pattern");
30
31 // Create a mutable String to hold the modified result
32 let mut result = String::new();
33 let mut last_end = 0;
34
35 // Iterate over all matches
36 for (index, caps) in regex.captures_iter(input).enumerate() {
37 // Get the matched value
38 let matched_value = &caps[0];
39
40 // Get the start index of the match
41 let start_index = caps.get(0).unwrap().start();
42
43 // Append the part of the string before the match
44 result.push_str(&input[last_end..start_index]);
45
46 // Call the replacement function with the index and matched value
47 result.push_str(&replacement(index, matched_value));
48
49 // Update the last end position
50 last_end = caps.get(0).unwrap().end();
51 }
52
53 // Append the remaining part of the input string after the last match
54 result.push_str(&input[last_end..]);
55
56 result
57}
58
59/// Handle the first character to be uppercase and others to be lowercase
60///
61/// If `otherslower` is `Some(true)`, the other characters will be converted to lowercase.
62/// If `otherslower` is `Some(false)`, the other characters will retain their original case.
63/// If `otherslower` is `None`, the other characters will also be converted to lowercase.
64///
65/// ```rs
66/// let res = str_first_upper("hello world", Some(true));
67/// assert_eq!(res, "Hello world");
68/// ```
69fn str_first_upper(s: &str, otherslower: Option<bool>) -> String {
70 let res: String = s
71 .chars()
72 .enumerate()
73 .map(|(i, c)| {
74 if i == 0 {
75 c.to_uppercase().to_string() // Capitalize the first character
76 } else {
77 match otherslower {
78 Some(false) => c.to_string(), // Retain original case if false
79 _ => c.to_lowercase().to_string(), // Convert to lowercase if true or None
80 }
81 }
82 })
83 .collect();
84
85 res
86}
87
88fn str_first_lower(s: &str) -> String {
89 let res: String = s
90 .chars()
91 .enumerate()
92 .map(|(i, c)| {
93 if i == 0 {
94 c.to_lowercase().to_string() // Capitalize the first character
95 } else {
96 c.to_string()
97 }
98 })
99 .collect();
100 res
101}
102
103/// add filled letters as prefix when enable and pattern match
104///
105/// ```rs
106/// res = str_pattern_prefix(&res, r"(?:[A-Z]+)", index != 0);
107/// ```
108fn str_pattern_prefix(s: &str, pattern: &str, filled: &str, enable: bool) -> String {
109 if enable {
110 let upper_case_pattern = Regex::new(pattern).unwrap();
111 upper_case_pattern.replace_all(s, format!("{}{}", filled, "$0")).to_string()
112 } else {
113 s.to_string()
114 }
115}
116
117/// padd letters when enable and pattern match
118///
119/// ```rs
120/// res = str_case_switch_when_enable(&res, index == 0);
121/// ```
122// fn str_case_switch_when_enable(s: &str, enable: bool) -> String {
123// if enable {
124// s.to_uppercase()
125// } else {
126// s.to_lowercase()
127// }
128// }
129
130fn baseify(input_string: &str) -> String {
131 // Define a regex pattern for camelCase words
132 // let pattern = r"(?:^\w|[A-Z_-]|\b\w)";
133 // let separator_pattern = Regex::new(r"[-_]+").unwrap();
134
135 // let debug = false;
136 // // Define a replacement function that uses the index
137 // let replacement_function = |index: usize, match_str: &str| {
138 // // info match key and val
139 // if debug {
140 // println!("{},{}", index, match_str);
141 // }
142
143 // // Replace multi - or _ with a space
144 // let res = separator_pattern.replace_all(match_str, " ").to_string();
145
146 // // Add space before uppercase letters that are not the first index
147 // // res = str_pattern_prefix(&res, r"(?:[A-Z]+)", " ", index != 0);
148
149 // // Handle the first character to be uppercase and others to be lowercase
150 // // res = str_first_upper(&match_str, None);
151
152 // // Capitalize the first character and lowercase the rest
153 // // res = str_case_switch_when_enable(&res, index == 0);
154 // res
155 // // format!("REPLACED_{}: {} ", index, match_str.to_lowercase())
156 // };
157 // let result = str_pattern_replace(input_string, pattern, replacement_function);
158
159 // step 1 - Replace multi - or _ with a space
160 let result = str_pattern_replace(input_string, r"[-_]+", |_index: usize, _match_str: &str| {
161 " ".to_string()
162 });
163 // println!("[replace multi - or _ with a space]: {}", result);
164
165 // optinal
166 // let filled as prefix to sequence of two or more uppercase letters
167 // let result = str_pattern_prefix(&result, r"(?:[A-Z]{2,})", " ", true);
168
169 // let frst char upper for sequence of two or more uppercase letters
170 let result =
171 str_pattern_replace(&result, r"(?:[A-Z]{2,})", |_index: usize, match_str: &str| {
172 str_first_upper(&match_str, None)
173 });
174 // println!("[NAME to Name]: {}", result);
175
176 // let filled as prefix to a uppercase letter
177 let result = str_pattern_prefix(&result, r"[A-Z]+", " ", true);
178 let result =
179 str_pattern_replace(&result, r" +", |_index: usize, _match_str: &str| " ".to_string());
180 // println!("[prefix space to uppercase letter]: {}", result);
181
182 // let word first char upper for each word
183 // step 2 - Capitalize the first character and lowercase the rest for each word
184 let words_pattern = r"(?:[\w]+)";
185 let words_first_upper = |_index: usize, match_str: &str| -> String {
186 // str_case_switch_when_enable(&match_str, index == 0)
187 str_first_upper(&match_str, None)
188 };
189 let result = str_pattern_replace(&result, words_pattern, words_first_upper);
190
191 // println!("[word first upper]: {}", result);
192
193 // step 3 - let str first char upper for sentence
194 // let result = str_first_upper(&result, None);
195 // println!("[sentence first upper]: {}", result);
196
197 result
198}
199
200///
201///
202/// ```rs
203/// assert_eq!(humanize("hello-world"), "Hello World");
204/// assert_eq!(humanize("hello_world"), "Hello World");
205/// assert_eq!(humanize("helloWorld"), "Hello World");
206/// assert_eq!(humanize("HelloWorld"), "Hello World");
207/// assert_eq!(humanize("helloWORLD"), "Hello World");
208/// assert_eq!(humanize(""), "");
209/// assert_eq!(humanize("--"), "");
210/// assert_eq!(humanize("__"), "");
211/// assert_eq!(humanize("hello--world"), "Hello World");
212/// assert_eq!(humanize("hello__world"), "Hello World");
213/// assert_eq!(humanize("helloWORLD Test"), "Hello World Test");
214/// ```
215pub fn humanize(s: &str) -> String {
216 // use regexp to get words in rust: "\w+"
217 // let words support containts - or _ "[\w-]+"
218 // (?:^\w|[A-Z_-]|\b\w)
219 // r"(?:^\w|[A-Z-a-z]|\b\w)"
220
221 // (?:^\w|[A-Z_-]|\b\w)
222 // (?:(?m)^\w|[A-Z_-]|\b\w)
223 // Regex to match the patterns similar to the TypeScript regex
224 let result = baseify(s);
225 // Trim any trailing whitespace and return
226 result.trim().to_string().replace("\n", " ") // Replace newlines with spaces
227}
228
229///
230/// ```rs
231/// assert_eq!(slugify("hello-world"), "hello-world");
232/// assert_eq!(slugify("hello_world"), "hello-world");
233/// assert_eq!(slugify("helloWorld"), "hello-world");
234/// assert_eq!(slugify("HelloWorld"), "hello-world");
235/// assert_eq!(slugify("helloWORLD"), "hello-world");
236/// assert_eq!(slugify(""), "");
237/// assert_eq!(slugify("--"), "");
238/// assert_eq!(slugify("__"), "");
239/// assert_eq!(slugify("hello--world"), "hello-world");
240/// assert_eq!(slugify("hello__world"), "hello-world");
241/// assert_eq!(slugify("helloWORLD Test"), "hello-world-test");
242/// ```
243pub fn slugify(s: &str) -> String {
244 let humanized = humanize(s);
245 humanized.to_lowercase().replace(" ", "-")
246}
247
248///
249///
250/// ```rs
251/// assert_eq!(camelize("hello-world"), "helloWorld");
252/// assert_eq!(camelize("hello_world"), "helloWorld");
253/// assert_eq!(camelize("helloWorld"), "helloWorld");
254/// assert_eq!(camelize("HelloWorld"), "helloWorld");
255/// assert_eq!(camelize("helloWORLD"), "helloWorld");
256/// assert_eq!(camelize(""), "");
257/// assert_eq!(camelize("--"), "");
258/// assert_eq!(camelize("__"), "");
259/// assert_eq!(camelize("hello--world"), "helloWorld");
260/// assert_eq!(camelize("hello__world"), "helloWorld");
261/// assert_eq!(camelize("helloWORLD Test"), "helloWorldTest");
262/// ```
263pub fn camelize(s: &str) -> String {
264 let humanized = humanize(s);
265
266 let result = str_pattern_replace(
267 &str_first_lower(&humanized),
268 r" +",
269 |_index: usize, _match_str: &str| "".to_string(),
270 );
271
272 // let mut result = String::new();
273 // let mut first_char = true;
274 // for c in humanized.chars() {
275 // if c == ' ' {
276 // continue;
277 // }
278 // if first_char {
279 // result.push(c.to_ascii_lowercase());
280 // first_char = false;
281 // } else {
282 // result.push(c.to_ascii_uppercase());
283 // }
284 // }
285 result
286}
287
288///
289///
290/// ```rs
291/// assert_eq!(underscoped("hello-world"), "hello_world");
292/// assert_eq!(underscoped("hello_world"), "hello_world");
293/// assert_eq!(underscoped("helloWorld"), "hello_world");
294/// assert_eq!(underscoped("HelloWorld"), "hello_world");
295/// assert_eq!(underscoped("helloWORLD"), "hello_world");
296/// assert_eq!(underscoped(""), "");
297/// assert_eq!(underscoped("--"), "");
298/// assert_eq!(underscoped("__"), "");
299/// assert_eq!(underscoped("hello--world"), "hello_world");
300/// assert_eq!(underscoped("hello__world"), "hello_world");
301/// assert_eq!(underscoped("helloWORLD Test"), "hello_world_test");
302/// ``````
303pub fn underscoped(s: &str) -> String {
304 let humanized = humanize(s);
305 humanized.to_lowercase().replace(" ", "_")
306}
307
308/// transform string to class style
309///
310/// ```rs
311/// assert_eq!(classify("hello-world"), "HelloWorld");
312/// assert_eq!(classify("hello_world"), "HelloWorld");
313/// assert_eq!(classify("helloWorld"), "HelloWorld");
314/// assert_eq!(classify("HelloWorld"), "HelloWorld");
315/// assert_eq!(classify("helloWORLD"), "HelloWorld"); //different for zero's stre in ts
316/// assert_eq!(classify(""), "");
317/// assert_eq!(classify("--"), "");
318/// assert_eq!(classify("__"), "");
319/// assert_eq!(classify("hello--world"), "HelloWorld");
320/// assert_eq!(classify("hello__world"), "HelloWorld");
321/// assert_eq!(classify("helloWORLD Test"), "HelloWorldTest");
322/// ```
323pub fn classify(s: &str) -> String {
324 let humanized = humanize(s);
325 let result = str_pattern_replace(
326 &str_first_lower(&humanized),
327 r"\w+",
328 |_index: usize, _match_str: &str| str_first_upper(_match_str, Some(true)),
329 );
330 result.replace(" ", "")
331}
332
333///
334///
335/// ```rs
336/// assert_eq!(swap_case("hello"), "HELLO");
337/// assert_eq!(swap_case("HELLO"), "hello");
338/// assert_eq!(swap_case("Hello"), "hELLO");
339/// assert_eq!(swap_case(""), "");
340/// assert_eq!(swap_case("HeLlO"), "hElLo");
341/// ```
342pub fn swap_case(s: &str) -> String {
343 let mut result = String::new();
344 for c in s.chars() {
345 if c.is_uppercase() {
346 result.push(c.to_ascii_lowercase());
347 } else {
348 result.push(c.to_ascii_uppercase());
349 }
350 }
351 result
352}
353
354/// ttransform the first char to upper case (only the first word), other noop
355///
356/// ```rs
357/// assert_eq!(capitalize("hello"), "Hello");
358/// assert_eq!(capitalize("HELLO"), "HELLO");
359/// assert_eq!(capitalize("Hello"), "Hello");
360/// assert_eq!(capitalize(""), "");
361/// assert_eq!(capitalize("hello world"), "Hello world");
362/// ```
363pub fn capitalize(s: &str) -> String {
364 let mut result = String::new();
365 let mut first_char = true;
366 for c in s.chars() {
367 if first_char {
368 result.push(c.to_ascii_uppercase());
369 first_char = false;
370 } else {
371 result.push(c);
372 }
373 }
374 result
375}
376
377/// transform the firt char to upper (only the first word) , other lower
378///
379/// ```rs
380/// assert_eq!(sentence("hello"), "Hello");
381/// assert_eq!(sentence("HELLO"), "Hello");
382/// assert_eq!(sentence("Hello"), "Hello");
383/// assert_eq!(sentence(""), "");
384/// assert_eq!(sentence("hello world"), "Hello world");
385/// assert_eq!(sentence("HELLO WORLD"), "Hello world");
386/// ```
387pub fn sentence(s: &str) -> String {
388 let mut result = String::new();
389 let mut first_char = true;
390 for c in s.chars() {
391 if first_char {
392 result.push(c.to_ascii_uppercase());
393 first_char = false;
394 } else {
395 result.push(c.to_ascii_lowercase());
396 }
397 }
398 result
399}
400
401/// transform the firt char to upper(for each word), other lower
402///
403/// ```rs
404/// assert_eq!(titleize("hello"), "Hello");
405/// assert_eq!(titleize("HELLO"), "Hello");
406/// assert_eq!(titleize("Hello"), "Hello");
407/// assert_eq!(titleize("hello world"), "Hello World");
408/// assert_eq!(titleize("HELLO WORLD"), "Hello World");
409/// assert_eq!(titleize(""), "");
410/// assert_eq!(titleize("hello--world"), "Hello World");
411/// assert_eq!(titleize("hello__world"), "Hello World");
412/// ```
413pub fn titleize(s: &str) -> String {
414 let humanized = humanize(s);
415 let mut result = String::new();
416 let words = humanized.split_whitespace();
417 for word in words {
418 let capitalized_word = word.chars().next().unwrap().to_ascii_uppercase().to_string()
419 + &word[1..].to_ascii_lowercase();
420 result.push_str(&capitalized_word);
421 result.push(' ');
422 }
423 result.trim_end().to_string()
424}
425
426pub fn pad_start(s: &str, len: usize, filled: char) -> String {
427 let mut result = s.to_string();
428 while result.len() < len {
429 result.insert(0, filled);
430 }
431 result
432}
433
434pub fn pad_end(s: &str, len: usize, filled: char) -> String {
435 let mut result = s.to_string();
436 while result.len() < len {
437 result.push(filled);
438 }
439 result
440}
441
442#[cfg(test)]
443mod lib_test;