基于Rust实现的文本搜索minigrep

在Rust学习社区看到了 用Rust语言实现的minigrep,对于初学者的我来说,这个项目很感兴趣,于是跟着实现了一遍,并完善了一点逻辑,以下是对项目的介绍

效果展示

本次演示介绍针对原作者代码程序的查询逻辑做了一点点小的优化,原程序逻辑的查询是放在了程序运行的时候,逻辑修改后启动的时候可以添加参数,也可以启动后添加,具体如下
修改前

查询时 需要输入查询的字符串和文件
cargo run -- th poem.txt

修改后

  1. 启动程序:cargo run
  2. 输入要查询的字符串 th
  3. 输入要查询的文件路径 poem.txt
  4. 查询到的结果:
    Then there’s a pair of us - don’t tell!
    They’d banish us, you know.
    To tell your name the livelong day
  5. 退出程序:输入:q

如下图所示
在这里插入图片描述

代码实现

代码结构

minigrep
├── Cargo.lock
├── Cargo.toml
├── output.txt
├── poem.txt
├── src
    ├── lib.rs
    └── main.rs

代码展示

/src/main.rs

use std::{env, process};
use std::io::stdin;
use minigrep::Config;
fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() == 1 {
        // 如果没输入查询参数,就循环等待用户的输入
        loop {
            println!("请输入要查询的字符串:");
            // 等待用户输入
            let mut input = String::new();
            stdin().read_line(&mut input).expect("无法读取");
            let mut args = input.split_whitespace();
            let mut a = String::new();
            let query = args.next().unwrap_or_else(|| {
                println!("请输入有效的查询字符串");
                stdin().read_line(&mut a);
                &a.as_str().trim()
            });
            if(":q".eq(query.clone())){
                println!("程序退出");
                process::exit(1);
            }
            let mut a = String::new();
            let file_path = args.next().unwrap_or_else(|| {
                println!("请输入文件路径:");
                stdin().read_line(&mut a);
                &a.as_str().trim()
            });
            let config1 = Config { query: query.to_string(), file_path: file_path.to_string(), ignore_case: true };
            if let Err(e) = minigrep::run(config1) {
                eprintln!("程序出错:{e}");
            }
        }
    } else {
        // 启动时的入参
        let config = Config::build(env::args()).unwrap_or_else(|err| {
            eprintln!("程序解析 参数异常 {err}");
            process::exit(1);
        });

        println!("search for {}", config.query);
        println!("in file {}", config.file_path);

        if let Err(e) = minigrep::run(config) {
            eprintln!("程序出错:{e}");
            process::exit(1);
        }
    }
}


/src/lib.rs

use std::error::Error;
use std::{env, fs};

// 查询业务逻辑
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    if let Ok(contents) = fs::read_to_string(config.file_path){
        let lines = if config.ignore_case {
            search_case_insensitive(&config.query, &contents)
        } else {
            search(&config.query, &contents)
        };
        println!("查询到的结果:");
        for line in lines {
            println!("{line}")
        }
        Ok(())
    }else {
        Err(Box::from("未查询到文件"))
    }
}

// 配置实体
pub struct Config {
    pub query: String,
    pub file_path: String,
    pub ignore_case:bool,
}
impl Config {

    // 构建配置实体
    pub fn build(mut args: impl Iterator<Item =String>) -> Result<Config, &'static str> {
        let _programeName = args.next();
        let query = match args.next() {
            Some(query) => query,
            None => return Err("未获取到 要查询的 字符串参数"),
        };
        let file_path = match args.next() {
            Some(file_path) => file_path,
            None => return Err("未获取到文件路径"),
        };
        // 从环境变量中找到是否包含 IGNORE_CASE
        let ignore_case =  env::var("IGNORE_CASE").is_ok();
        Ok(Config { query, file_path ,ignore_case})
    }
}

// 对参数解析
fn parse_config(args: &[String]) -> Config {
    let query = args[1].clone();
    let file_path = args[2].clone();
    let ignore_case =  env::var("IGNORE_CASE").is_ok();
    Config { query, file_path ,ignore_case}
}
// 大小写敏感查询
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.contains(query))
        .collect()
}
// 忽略大小写查询
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
        .collect()
}


// 测试模块
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn one_result() {
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.";

        assert_eq!(vec!["safe, fast, productive."], search(query, contents))
    }

    #[test]
    fn test_case_insensitive() {
        let query = "RusT";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.";
        assert_eq!(vec!["Rust:"], search_case_insensitive(query, contents))
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值