minigrep_jimloop/
lib.rs

1//! # minigrep_jimloop
2//!
3//! `minigrep_jimloop` is a custom shell tool,you can search String from a file.
4//! # useage
5//!  <b>minigrep_jimloop -s query_str -f file_path -i </b>
6//!
7//!  minigrep_jimloop -s 'to' -f poem.txt -i
8//!
9
10
11
12use std::error::Error;
13use std::fs;
14use std::env;
15use std::env::Args;
16use std::process;
17use clap::{Parser,ColorChoice};
18
19
20
21#[derive(Parser, Debug)]
22#[command(
23name = "minigrep_jimloop-tool",
24version = "1.0",
25about = "minigrep_jimloop-tool 🎯,基于rust编写",
26long_about = None,
27override_usage = "minigrep_jimloop [EXE] -i <IGNORE_CASE> -s <STRING> -f <FILE>",
28color = ColorChoice::Always,
29)]
30pub struct Config{
31    #[arg(short = 's',long)]
32    pub query:String,
33    #[arg(short = 'f', long, help = r#"指定搜索文件的路径"#)]
34    pub file_path:String,
35    #[arg(short = 'i',long,default_value_t=false)]
36    pub ignore_case:bool,
37}
38
39impl Config{
40    pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config,&'static str>{
41        args.next();
42        let query:String = match args.next(){
43            None => return Err("Didn't get a query string."),
44            Some(arg) => arg,
45        };
46        let file_path:String = match args.next(){
47            None => return Err("Didn't get a file path."),
48            Some(arg) => arg,
49        };
50        let mut ignore_case:bool = false;
51        match args.next(){
52            Some(arg) =>  if arg=="true" || arg=="1" {ignore_case = true},
53            _ => { ignore_case = false},
54        };
55        if !ignore_case{
56            ignore_case = env::var("IGNORE_CASE").is_ok();
57        }
58        Ok(Config{ query, file_path,ignore_case})
59    }
60}
61
62pub fn run()-> Result<(),Box<dyn Error>>{
63    let config = Config::parse();
64    let contents:String = fs::read_to_string(config.file_path)?;
65    let results = if config.ignore_case{
66        search_case_insensitive(&config.query,&contents)
67    }else {
68        search(&config.query,&contents)
69    };
70    for line in results{
71        println!("{}",line);
72    }
73    Ok(())
74}
75
76
77pub fn run_with_args()-> Result<(),Box<dyn Error>>{
78    let args:Args = env::args();
79    let config = Config::build(args).unwrap_or_else(|err|{
80        eprintln!("Problem parsing arguments: {err}");
81        process::exit(1);
82    });
83    let contents:String = fs::read_to_string(&config.file_path)?;
84    let results = if config.ignore_case{
85        search_case_insensitive(&config.query,&contents)
86    }else {
87        search(&config.query,&contents)
88    };
89    for line in results{
90        println!("{}",line);
91    }
92    Ok(())
93}
94
95//区分大小写
96pub fn search<'a>(query:&str,contents:&'a str) -> Vec<&'a str>{
97    contents
98        .lines()
99        .filter(|line| { line.contains(query) })
100        .collect()
101}
102
103
104// # minigrep_jimloop
105//
106// `minigrep_jimloop` is a custom shell like `grep`,can search String from file.
107
108///查询大小写不敏感且满足条件的行
109/// # Examples
110/// ```
111/// let query = String::from("to");
112/// let contents = String::from("Do you want to go somewhere?\n
113/// I want.");
114/// let results = minigrep_jimloop::search_case_insensitive(&query,&contents);
115/// assert_eq!(results,vec!["Do you want to go somewhere?"])
116/// ```
117///
118///
119pub fn search_case_insensitive<'a>(query:&str,contents:&'a str) -> Vec<&'a str>{
120    contents
121        .lines()
122        .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
123        .collect()
124}