zzq_minigrep/
lib.rs

1//! # Minigrep
2//!
3//! `minigrep` 是用来在文件中查找相关字符串的工具类
4
5use std::{env, fs};
6use std::error::Error;
7
8
9/// 根据配置参数信息运行,查找文件里面的文本和query一致的信息
10///
11/// # Examples
12///
13/// ```
14/// use std::process;
15/// use std::env;
16/// use zzq_minigrep::Config;
17/// let config =Config::build(env::args()).unwrap_or_else(|err| {
18///         // println!("参数解析错误:{err}");
19///         eprintln!("参数解析错误:{err}");
20///         process::exit(1);
21///     });
22/// if let Err(e) = zzq_minigrep::run(config) {
23///         // println!("Application error: {e}");
24///         eprintln!("Application error: {e}");
25///         process::exit(1);
26///     }
27/// ```
28pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
29    let contents = fs::read_to_string(config.file_path)?;
30    // println!("\nWith text:\n{contents}");
31
32    // for line in search(&config.query, &contents) {
33    //     println!("{line}");
34    // }
35    let results = if config.ignore_case {
36        search_case_insensitive(&config.query, &contents)
37    } else {
38        search(&config.query, &contents)
39    };
40    for line in results {
41        println!("{line}");
42    }
43    Ok(())
44}
45
46fn parse_config2(args: &[String]) -> (&str, &str) {
47    let query = &args[1];
48    let file_path = &args[2];
49    (query, file_path)
50}
51
52/// 输入配置实体类
53///
54pub struct Config {
55    pub query: String,
56    pub file_path: String,
57    pub ignore_case: bool,
58}
59
60/// Adds one to the number given.
61///
62/// # Examples
63///
64/// ```
65/// let arg = 5;
66/// let answer = zzq_minigrep::add_one(arg);
67///
68/// assert_eq!(6, answer);
69/// ```
70pub fn add_one(x: i32) -> i32 {
71    x + 1
72}
73
74impl Config {
75    //=======v1
76    // fn new(args: &[String]) -> Config {
77    //     if args.len() < 3 {
78    //         panic!("参数不足,请输入查询关键词和文件名称,比如:\r\n minigrep test filename.txt")
79    //     }
80    //     let query = args[1].clone();
81    //     let file_path = args[2].clone();
82    //     Config { query, file_path }
83    // }
84    ////=======v2
85    // pub fn build(args: &[String]) -> Result<Config, &'static str> {
86    //     if args.len() < 3 {
87    //         // panic!("")
88    //         return Err("参数不足,请输入查询关键词和文件名称,比如:\r\n minigrep test filename.txt");
89    //     }
90    //     let query = args[1].clone();
91    //     let file_path = args[2].clone();
92    //     let ignore_case = env::var("IGNORE_CASE").is_ok();
93    //     Ok(Config { query, file_path, ignore_case  })
94    // }
95    ////=======v3
96    /// 根据输入参数来构造配置实体信息
97    /// 第一个参数是查询的文本信息
98    /// 第二个参数是文件信息
99    /// 具体为:minigrep test test.txt
100    pub fn build(mut args: impl Iterator<Item=String>) -> Result<Config, &'static str> {
101        args.next();
102        let query = match args.next() {
103            Some(arg) => arg,
104            None => return Err("没有查询参数,请输入查询字符串……")
105        };
106        let file_path = match args.next() {
107            Some(arg) => arg,
108            None => return Err("没有输入文件地址参数")
109        };
110        let ignore_case = env::var("IGNORE_CASE").is_ok();
111
112        Ok(Config {
113            query,
114            file_path,
115            ignore_case,
116        })
117    }
118}
119
120// fn parse_config(args: &[String]) -> Config {
121//     Config::new(&args)
122// }
123
124/// Iterate through each line of the contents.
125///Check whether the line contains our query string.
126/// If it does, add it to the list of values we’re returning.
127/// If it doesn’t, do nothing.
128/// Return the list of results that match.
129// pub fn search(query: &str, contents: &str) -> Vec<&str> {// expect a named lifetime parameter
130pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
131    ////=======v1
132    // let mut results = vec![];
133    // for line in contents.lines() {
134    //     if line.contains(query) {
135    //         results.push(line);
136    //     }
137    // }
138    // results
139
140    ////=======v2
141    // let mut results = Vec::new();
142    contents.lines().filter(|line| line.contains(query)).collect()
143    // results
144}
145
146///大小写敏感搜索
147pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
148    let query = query.to_lowercase();
149    let mut results = Vec::new();
150    for line in contents.lines() {
151        if line.to_lowercase().contains(&query) {
152            results.push(line);
153        }
154    }
155    results
156}
157
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn one_result() {
165        let query = "我";
166        let contents = "\
167        这是一个我
168s是一个还可以的rust学习者,
169天下无双
170        ";
171        assert_eq!(vec!["这是一个我"], search(query, contents));
172    }
173
174    #[test]
175    fn one_result_2() {
176        let query = "duct";
177        let contents = "\
178Rust:
179safe, fast, productive.
180Pick three.";
181
182        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
183    }
184
185    #[test]
186    fn case_insensitive() {
187        let query = "rUsT";
188        let contents = "\
189Rust:
190safe, fast, productive.
191Pick three.
192Trust me.";
193
194        assert_eq!(
195            vec!["Rust:", "Trust me."],
196            search_case_insensitive(query, contents)
197        );
198    }
199}