csv_csp/
lib.rs

1/*
2    My attempt at csv parser
3    2022-11-25  Sven Ponelat
4*/
5
6
7
8use std::fs::*;
9use std::io::{self, BufRead};
10use std::path::Path;
11
12
13
14// function to convert a csv file to a vector of a vector of strings
15pub fn csv_get_str_vec(file: &str, num_fields: usize, skip: i32, delimiter: &str) -> Result<Vec<Vec<String>>, String> {
16    let mut ret: Vec<Vec<String>> = Vec::new();
17    let mut line_counter = 0;
18
19    // File hosts must exist in current path before this produces output
20    if let Ok(lines) = read_lines(file) {
21        // Consumes the iterator, returns an (Optional) String
22        for line in lines {
23            line_counter += 1;
24
25            if line_counter > skip {
26                // process line
27                if let Ok(ip) = line {
28                    let split = ip.split(delimiter);
29                    let vec_str: Vec<&str> = split.collect();
30                    let len = vec_str.len();
31                    if len != num_fields {
32                        let message = format!("Line {} in the file \"{}\" does not contain {} fields!",line_counter, file, num_fields);
33                        return Err(message);
34                    }
35
36                    // convert the &str to Strings and make a vector
37                    let mut to_be_pushed: Vec<String> = Vec::new(); 
38                    for s in vec_str {
39                        to_be_pushed.push(s.to_string());
40                    }
41
42                    // add the new vector to the collection of vectors
43                    ret.push(to_be_pushed);
44                }
45                else {
46                    let message = format!("Error in reading line {} in the file \"{}\"",line_counter, file);
47                    return Err(message);
48                }
49            }
50            else {
51                continue;
52            }
53        }
54    }
55    else {
56        let message = format!("Error in opening the file \"{}\"",file);
57        return Err(message);
58    }
59
60    if ret.len() == 0 {
61        let message = format!("The output vector has no no data!");
62        return Err(message); 
63    }
64
65    Ok(ret)
66}
67
68
69// The output is wrapped in a Result to allow matching on errors
70// Returns an Iterator to the Reader of the lines of the file.
71fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
72where P: AsRef<Path>, {
73    let file = File::open(filename)?;
74    Ok(io::BufReader::new(file).lines())
75}
76
77
78
79
80
81
82
83
84
85
86
87
88// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  Tests  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
89// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    
96    // #[ignore]
97    #[test]
98    fn t001_first() {
99        let source = "./test/some-documents/small.csv";
100        let destination = "./test/work.csv";
101        copy(source,destination).expect("Failed to copy");
102        let res_veccy = csv_get_str_vec(destination,6, 2,";");
103        remove_file(destination).expect("Cleanup test failed");
104
105        assert!(res_veccy.is_ok());
106    }
107
108    // #[ignore]
109    #[test]
110    fn t002_failures() {
111        // no lines
112        let source = "./test/some-documents/no-rows.csv";
113        let destination = "./test/work.csv";
114        copy(source,destination).expect("Failed to copy");
115        let res_veccy = csv_get_str_vec(destination,6, 2,";");
116        remove_file(destination).expect("Cleanup test failed");
117        assert!(res_veccy.is_err());
118
119        // one line too little fields
120        let source = "./test/some-documents/too-little.csv";
121        let destination = "./test/work.csv";
122        copy(source,destination).expect("Failed to copy");
123        let res_veccy = csv_get_str_vec(destination,6, 2,";");
124        remove_file(destination).expect("Cleanup test failed");
125        assert!(res_veccy.is_err());
126
127        // one line too many fields
128        let source = "./test/some-documents/too-many.csv";
129        let destination = "./test/work.csv";
130        copy(source,destination).expect("Failed to copy");
131        let res_veccy = csv_get_str_vec(destination,6, 2,";");
132        remove_file(destination).expect("Cleanup test failed");
133        assert!(res_veccy.is_err());
134
135        // one line blank
136        let source = "./test/some-documents/blank.csv";
137        let destination = "./test/work.csv";
138        copy(source,destination).expect("Failed to copy");
139        let res_veccy = csv_get_str_vec(destination,6, 2,";");
140        remove_file(destination).expect("Cleanup test failed");
141        assert!(res_veccy.is_err());
142
143    }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162} //end of tests
163
164