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}