Advertisement
Guest User

Untitled

a guest
Nov 15th, 2023
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 4.27 KB | None | 0 0
  1. use std::cmp::{max, min};
  2.  
  3. /// This function receives an array of words, formats the line, adds spaces as
  4. /// neccessary and returns the result.
  5. ///
  6. /// * `words` - An array of words to be joined.
  7. /// * `chars` - The total amount of chars in words (excluding spaces and whitespaces).
  8. /// * `max_width` - The maximum allowed width that line can have.
  9. fn format_line(words: &[&str], chars: usize, max_width: usize) -> String {
  10.     // Calculate the interval between words (doesn't count the first word)
  11.     let interval = max(words.len() - 1, 1);
  12.     // Calculate the maximum amount of spaces we can insert
  13.     let free_space = max_width - min(chars, max_width);
  14.     // Divide available amount of spaces by interval
  15.     let spaces = free_space / interval;
  16.     // In case if we have an uneven amount of spaces
  17.     let extra = free_space % interval;
  18.  
  19.     let mut formatted = String::new();
  20.     for (index, word) in words.iter().enumerate() {
  21.         formatted.push_str(word);
  22.         // If we have only one word or if we have more words
  23.         if words.len() == 1 || words.len() != index + 1 {
  24.             formatted.push_str(" ".repeat(spaces).as_str());
  25.         }
  26.         // If we have an extra space
  27.         if index < extra {
  28.             formatted.push_str(" ");
  29.         }
  30.     }
  31.  
  32.     formatted
  33. }
  34.  
  35. /// An algorithm to break string into chucks with pre-defined lenght. The intervals between
  36. /// words will be filled with spaces.
  37. ///
  38. /// * `input` - An input string to be processed.
  39. /// * `line_width` - The maximum allowed width of the line (aka chunk size).
  40. pub fn transform(input: &str, line_width: u32) -> String {
  41.     let width = line_width.try_into().unwrap();
  42.  
  43.     let result = match input.len() {
  44.         0 => input.to_owned(),
  45.         w if w < width => {
  46.             format!("{}{}", input, format_args!("{: >1$}", "", width - w))
  47.         }
  48.         w if w >= width => {
  49.             // Create an array of words splitted by whitespace
  50.             let words = input.split_whitespace().collect::<Vec<&str>>();
  51.             let mut formatted: Vec<String> = Vec::new();
  52.             let mut word_chars = 0;
  53.             let mut spaces = 0;
  54.             let mut start_cut = 0;
  55.  
  56.             for (index, word) in words.iter().enumerate() {
  57.                 word_chars += word.len();
  58.  
  59.                 let line_lenght = word_chars + spaces;
  60.                 let next_word_lenght = words.get(index + 1).unwrap_or(&"").len();
  61.                 let total = if next_word_lenght > 0 {
  62.                     line_lenght + next_word_lenght + 1
  63.                 } else {
  64.                     line_lenght
  65.                 };
  66.  
  67.                 spaces += 1;
  68.  
  69.                 // Check if the line has reached the capacity to place another word.
  70.                 // It also takes into account spaces between words.
  71.                 if (line_lenght <= width && (total > width || next_word_lenght == 0))
  72.                     || word.len() > width
  73.                 {
  74.                     // Select words for further transformation
  75.                     formatted.push(format_line(
  76.                         &words[start_cut..start_cut + spaces],
  77.                         word_chars,
  78.                         width,
  79.                     ));
  80.  
  81.                     // Finish line processing by clearning counters
  82.                     spaces = 0;
  83.                     word_chars = 0;
  84.                     start_cut = index + 1;
  85.                 }
  86.             }
  87.  
  88.             formatted.join("\n")
  89.         }
  90.         _ => "".to_owned(),
  91.     };
  92.  
  93.     result
  94. }
  95.  
  96. #[cfg(test)]
  97. mod tests {
  98.     use super::transform;
  99.  
  100.     #[test]
  101.     fn simple() {
  102.         let test_cases = [
  103.             ("", 5, ""),
  104.             ("test", 5, "test "),
  105.             ("Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", 12,
  106.              "Lorem  ipsum\ndolor    sit\namet        \nconsectetur \nadipiscing  \nelit  sed do\neiusmod     \ntempor      \nincididunt  \nut labore et\ndolore magna\naliqua      "),
  107.             ("Lorem     ipsum    dolor", 17, "Lorem ipsum dolor"),
  108.         ];
  109.  
  110.         for &(input, line_width, expected) in &test_cases {
  111.             println!("input: '{}'", input);
  112.             assert_eq!(transform(input, line_width), expected);
  113.         }
  114.     }
  115. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement