it编程 > 编程语言 > rust

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

173人参与 2024-08-09 rust

在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内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

Rust实现构建器模式和如何使用Bon库中的构建器

08-15

Rust 数据分析利器polars用法详解

08-20

【Rust光年纪】提升数据安全性与完整性:Rust语言哈希算法库深度对比

08-06

MySQL中的log_bin_trust_function_creators系统变量

09-02

Signature not supported. Hash algorithm SHA1 not available

08-02

Rust集合中向量和散列值映射表Hash Map与字符串

08-02

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论