Skip to content

Commit 057477b

Browse files
author
yaoming00
committed
feat: finish search query from file
1 parent bdc54c8 commit 057477b

File tree

4 files changed

+192
-14
lines changed

4 files changed

+192
-14
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ Cargo.lock
1010
**/*.rs.bk
1111

1212
.DS_Store
13+
output.txt

poem.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ How dreary to be somebody!
77
How public, like a frog
88
To tell your name the livelong day
99
To an admiring bog!
10+
11+
US
12+
13+
uS

src/lib.rs

Lines changed: 175 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
use std::{fs, error::Error};
1+
use std::{error::Error, fs, env};
22

33
pub struct Config {
44
pub query: String,
55
pub filename: String,
6+
pub is_sensitive: bool,
67
}
78

89
impl Config {
910
pub fn new(args: &[String]) -> Result<Config, &'static str> {
1011
if args.len() < 3 {
11-
return Err("not enough arguments")
12+
return Err("not enough arguments");
1213
}
1314
/*
1415
注意 vector 的第一个值 (args[0]) 是 "target/debug/grep",它是我们二进制文件的名称。
@@ -25,12 +26,182 @@ impl Config {
2526
在第一轮编写时拥有一个可以工作但有点低效的程序要比尝试过度优化代码更好一些。
2627
随着你对 Rust 更加熟练,将能更轻松的直奔合适的方法,不过现在调用 clone 是完全可以接受的。
2728
*/
28-
Ok(Config { query, filename })
29+
30+
// env::var 返回一个 Result,
31+
// 它在环境变量被设置时返回包含其值的 Ok 成员,
32+
// 并在环境变量未被设置时返回 Err 成员。
33+
let is_sensitive = env::var("IS_SENSITIVE").is_err();
34+
Ok(Config { query, filename, is_sensitive })
2935
}
3036
}
3137

3238
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
3339
let contents = fs::read_to_string(config.filename)?;
34-
println!("\nContents is: \n{}", contents);
40+
println!("Result of search is:");
41+
let res = if config.is_sensitive {
42+
search_sensitive(&config.query, &contents)
43+
} else {
44+
search_insensitive(&config.query, &contents)
45+
};
46+
for v in res {
47+
println!("{}", v)
48+
}
3549
Ok(())
50+
51+
}
52+
53+
pub fn search_sensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
54+
let mut res = vec![];
55+
for line in contents.lines() {
56+
if line.contains(query) {
57+
res.push(line);
58+
}
59+
}
60+
res
61+
}
62+
63+
pub fn search_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
64+
let mut res = vec![];
65+
for line in contents.lines() {
66+
if line.to_lowercase().contains(&query.to_lowercase()) {
67+
res.push(line);
68+
}
69+
}
70+
res
71+
}
72+
73+
#[cfg(test)]
74+
mod config_tests {
75+
use super::*;
76+
77+
#[test]
78+
fn test_4_new_config_1() -> Result<(), String> {
79+
let mut args: Vec<String> = vec!["".to_string()];
80+
args.push("query".to_string());
81+
args.push("filename".to_string());
82+
let config = Config::new(&args)?;
83+
assert_eq!(&config.query, &args[1]);
84+
assert_eq!(&config.filename, &args[2]);
85+
Ok(())
86+
}
87+
88+
#[test]
89+
fn test_4_new_config_2() -> Result<(), String> {
90+
let mut args: Vec<String> = vec!["".to_string()];
91+
args.push("query".to_string());
92+
args.push("filename".to_string());
93+
args.push("xxx".to_string());
94+
let config = Config::new(&args)?;
95+
assert_eq!(&config.query, &args[1]);
96+
assert_eq!(&config.filename, &args[2]);
97+
Ok(())
98+
}
99+
100+
#[test]
101+
#[should_panic]
102+
fn test_4_new_config_err() {
103+
let mut args: Vec<String> = vec!["".to_string()];
104+
args.push("query".to_string());
105+
let _res = Config::new(&args);
106+
let _config = match _res {
107+
Ok(config) => config,
108+
Err(err_str) => {
109+
panic!("{}", err_str)
110+
}
111+
};
112+
}
113+
114+
#[test]
115+
#[should_panic]
116+
fn test_4_new_config_err_2() {
117+
let args: Vec<String> = vec!["".to_string()];
118+
let _res = Config::new(&args);
119+
let _config = match _res {
120+
Ok(config) => config,
121+
Err(err_str) => {
122+
panic!("{}", err_str)
123+
}
124+
};
125+
}
126+
}
127+
128+
#[cfg(test)]
129+
mod run_tests {
130+
use super::*;
131+
132+
#[test]
133+
fn test_run() -> Result<(), String> {
134+
let mut args: Vec<String> = vec!["".to_string()];
135+
args.push("query".to_string());
136+
args.push("poem.txt".to_string());
137+
let config = Config::new(&args)?;
138+
139+
if let Err(e) = run(config) {
140+
assert_eq!("".to_string(), e.to_string())
141+
}
142+
Ok(())
143+
}
144+
145+
#[test]
146+
fn test_run_err() -> Result<(), String> {
147+
let mut args: Vec<String> = vec!["".to_string()];
148+
args.push("query".to_string());
149+
args.push("poemNotFound.txt".to_string());
150+
let config = Config::new(&args)?;
151+
152+
if let Err(e) = run(config) {
153+
assert_ne!("".to_string(), e.to_string())
154+
}
155+
Ok(())
156+
}
157+
}
158+
159+
#[cfg(test)]
160+
mod search_test {
161+
use super::*;
162+
163+
#[test]
164+
fn test_search_case_sensitive() {
165+
let query = "us";
166+
let contents = "\
167+
I'm nobody! Who are you?
168+
Are you nobody, too?
169+
Then there's a pair of us - don't tell!
170+
They'd banish us, you know.
171+
172+
How dreary to be somebody!
173+
How public, like a frog
174+
To tell your name the livelong day
175+
To an admiring bog!";
176+
assert_eq!(
177+
vec![
178+
" Then there's a pair of us - don't tell!",
179+
" They'd banish us, you know.",
180+
],
181+
search_sensitive(query, contents)
182+
)
183+
}
184+
185+
#[test]
186+
fn test_search_case_insensitive() {
187+
let query = "us";
188+
let contents = "US
189+
I'm nobody! Who are you?
190+
Are you nobody, too?
191+
Then there's a pair of us - don't tell!
192+
They'd banish us, you know.
193+
194+
How dreary to be somebody!
195+
How public, like a frog
196+
To tell your name the livelong day
197+
To an admiring bog!";
198+
assert_eq!(
199+
vec![
200+
"US",
201+
" Then there's a pair of us - don't tell!",
202+
" They'd banish us, you know.",
203+
],
204+
search_insensitive(query, contents)
205+
)
206+
}
36207
}

src/main.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1-
use std::{env, process};
21
use grep::Config;
2+
use std::{env, process};
33

44
fn main() {
55
let args: Vec<String> = env::args().collect();
66

7-
// unwrap_or_else:
7+
// unwrap_or_else:
88
// 当 Result 内部为 Err 时,传递 Err 给 err, 然后执行后面 {} 内的闭包,
99
// 当 Result 内部为 Ok 时, 返回其值给 config.
1010
let config = Config::new(&args).unwrap_or_else(|err| {
11-
println!("Parsing arguments: {}", err);
11+
eprintln!("Parsing arguments: {}", err);
1212
process::exit(1); // 表示程序出错退出
1313
});
1414

15-
println!("Search: {}", config.query);
16-
println!("in file: {}", config.filename);
17-
18-
if let Err(e) = grep::run(config) {
19-
println!("read file ERROR: {}", e);
20-
process::exit(1); // 表示程序出错退出
21-
}
15+
if let Err(e) = grep::run(config) {
16+
eprintln!("read file ERROR: {}", e);
17+
process::exit(1); // 表示程序出错退出
18+
}
2219
}
20+
21+
// Usage:
22+
// IS_SENSITIVE=1 cargo run us poem.txt
23+
// or
24+
// cargo run us poem.txt

0 commit comments

Comments
 (0)