buup/transformers/
line_number_remover.rs1use crate::{Transform, TransformError, TransformerCategory};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct LineNumberRemover;
6
7pub const DEFAULT_TEST_INPUT: &str = "1. First line\n2. Second line\n3. Third line";
9
10impl Transform for LineNumberRemover {
11 fn name(&self) -> &'static str {
12 "Line Number Remover"
13 }
14
15 fn id(&self) -> &'static str {
16 "linenumberremover"
17 }
18
19 fn description(&self) -> &'static str {
20 "Removes line numbers (and optional delimiters) from the beginning of each line."
21 }
22
23 fn category(&self) -> TransformerCategory {
24 TransformerCategory::Formatter
25 }
26
27 fn default_test_input(&self) -> &'static str {
28 ""
29 }
30
31 fn transform(&self, input: &str) -> Result<String, TransformError> {
32 let mut output = String::new();
33 for (i, line) in input.lines().enumerate() {
34 let trimmed_line = line.trim_start();
36 let first_char_idx = trimmed_line
37 .find(|c: char| !c.is_ascii_digit())
38 .unwrap_or(trimmed_line.len());
39
40 if trimmed_line[..first_char_idx]
42 .chars()
43 .all(|c| c.is_ascii_digit())
44 {
45 let content_start_idx = trimmed_line[first_char_idx..]
47 .find(|c: char| !c.is_whitespace() && !matches!(c, '.' | ':' | '-' | ')'))
48 .map(|idx| first_char_idx + idx)
49 .unwrap_or(trimmed_line.len()); output.push_str(&trimmed_line[content_start_idx..]);
51 } else {
52 output.push_str(line.trim_start()); }
55
56 if i < input.lines().count() - 1 || input.ends_with('\n') {
58 output.push('\n');
59 }
60 }
61 if input.is_empty() {
63 return Ok("".to_string());
64 }
65 if output.is_empty() && input.chars().all(|c| c == '\n') {
67 return Ok(input.to_string()); } else if !input.ends_with('\n') && output.ends_with('\n') {
69 output.pop();
71 }
72
73 Ok(output)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_line_number_remover() {
83 let transformer = LineNumberRemover;
84 assert_eq!(
85 transformer.transform(DEFAULT_TEST_INPUT).unwrap(),
86 "First line\nSecond line\nThird line"
87 );
88 assert_eq!(
89 transformer.transform("1 Hello\n2 World").unwrap(),
90 "Hello\nWorld"
91 );
92 assert_eq!(
93 transformer
94 .transform("1. First line\n2. Second line\n")
95 .unwrap(),
96 "First line\nSecond line\n"
97 );
98 assert_eq!(
99 transformer.transform("3:\tThird line").unwrap(),
100 "Third line"
101 );
102 assert_eq!(
103 transformer.transform("No leading number").unwrap(),
104 "No leading number"
105 );
106 assert_eq!(transformer.transform("").unwrap(), "");
107 assert_eq!(transformer.transform("1 \n2 \n").unwrap(), "\n\n"); assert_eq!(
109 transformer.transform("1 Line1\n\n3 Line3").unwrap(),
110 "Line1\n\nLine3"
111 ); assert_eq!(transformer.transform(" 4) Item 4").unwrap(), "Item 4"); assert_eq!(transformer.transform("5.").unwrap(), ""); assert_eq!(
115 transformer
116 .transform("Line without number\n6 Line with number")
117 .unwrap(),
118 "Line without number\nLine with number"
119 );
120 assert_eq!(transformer.transform("10- Item ten").unwrap(), "Item ten");
121 }
122}