Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::cmp::{max, min};
- /// This function receives an array of words, formats the line, adds spaces as
- /// neccessary and returns the result.
- ///
- /// * `words` - An array of words to be joined.
- /// * `chars` - The total amount of chars in words (excluding spaces and whitespaces).
- /// * `max_width` - The maximum allowed width that line can have.
- fn format_line(words: &[&str], chars: usize, max_width: usize) -> String {
- // Calculate the interval between words (doesn't count the first word)
- let interval = max(words.len() - 1, 1);
- // Calculate the maximum amount of spaces we can insert
- let free_space = max_width - min(chars, max_width);
- // Divide available amount of spaces by interval
- let spaces = free_space / interval;
- // In case if we have an uneven amount of spaces
- let extra = free_space % interval;
- let mut formatted = String::new();
- for (index, word) in words.iter().enumerate() {
- formatted.push_str(word);
- // If we have only one word or if we have more words
- if words.len() == 1 || words.len() != index + 1 {
- formatted.push_str(" ".repeat(spaces).as_str());
- }
- // If we have an extra space
- if index < extra {
- formatted.push_str(" ");
- }
- }
- formatted
- }
- /// An algorithm to break string into chucks with pre-defined lenght. The intervals between
- /// words will be filled with spaces.
- ///
- /// * `input` - An input string to be processed.
- /// * `line_width` - The maximum allowed width of the line (aka chunk size).
- pub fn transform(input: &str, line_width: u32) -> String {
- let width = line_width.try_into().unwrap();
- let result = match input.len() {
- 0 => input.to_owned(),
- w if w < width => {
- format!("{}{}", input, format_args!("{: >1$}", "", width - w))
- }
- w if w >= width => {
- // Create an array of words splitted by whitespace
- let words = input.split_whitespace().collect::<Vec<&str>>();
- let mut formatted: Vec<String> = Vec::new();
- let mut word_chars = 0;
- let mut spaces = 0;
- let mut start_cut = 0;
- for (index, word) in words.iter().enumerate() {
- word_chars += word.len();
- let line_lenght = word_chars + spaces;
- let next_word_lenght = words.get(index + 1).unwrap_or(&"").len();
- let total = if next_word_lenght > 0 {
- line_lenght + next_word_lenght + 1
- } else {
- line_lenght
- };
- spaces += 1;
- // Check if the line has reached the capacity to place another word.
- // It also takes into account spaces between words.
- if (line_lenght <= width && (total > width || next_word_lenght == 0))
- || word.len() > width
- {
- // Select words for further transformation
- formatted.push(format_line(
- &words[start_cut..start_cut + spaces],
- word_chars,
- width,
- ));
- // Finish line processing by clearning counters
- spaces = 0;
- word_chars = 0;
- start_cut = index + 1;
- }
- }
- formatted.join("\n")
- }
- _ => "".to_owned(),
- };
- result
- }
- #[cfg(test)]
- mod tests {
- use super::transform;
- #[test]
- fn simple() {
- let test_cases = [
- ("", 5, ""),
- ("test", 5, "test "),
- ("Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", 12,
- "Lorem ipsum\ndolor sit\namet \nconsectetur \nadipiscing \nelit sed do\neiusmod \ntempor \nincididunt \nut labore et\ndolore magna\naliqua "),
- ("Lorem ipsum dolor", 17, "Lorem ipsum dolor"),
- ];
- for &(input, line_width, expected) in &test_cases {
- println!("input: '{}'", input);
- assert_eq!(transform(input, line_width), expected);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement