Rust语言

关注公众号 jb51net

关闭
首页 > 软件编程 > Rust语言 > Rust 文本搜索minigrep

如何基于Rust实现文本搜索minigrep

作者:yoho-zhang

这篇文章主要介绍了基于Rust实现的文本搜索minigrep,本次演示介绍针对原作者代码程序的查询逻辑做了一点点小的优化,原程序逻辑的查询是放在了程序运行的时候,逻辑修改后启动的时候可以添加参数,也可以启动后添加,需要的朋友可以参考下

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

效果展示

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

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

修改后

启动程序:cargo run输入要查询的字符串 th输入要查询的文件路径 poem.txt查询到的结果:
Then there’s a pair of us - don’t tell!
They’d banish us, you know.
To tell your name the livelong day退出程序:输入: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))
    }
}

到此这篇关于基于Rust实现的文本搜索minigrep的文章就介绍到这了,更多相关Rust 文本搜索minigrep内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文