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

 更新时间:2024年08月09日 11:44:02   作者: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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在Rust中编写自定义Error的详细代码

    在Rust中编写自定义Error的详细代码

    Result<T, E> 类型可以方便地用于错误传导,Result<T, E>是模板类型,实例化后可以是各种类型,但 Rust 要求传导的 Result 中的 E 是相同类型的,所以我们需要编写自己的 Error 类型,本文给大家介绍了在Rust中编写自定义Error的详细代码,需要的朋友可以参考下
    2024-01-01
  • 详解Rust中的workspace

    详解Rust中的workspace

    这篇文章主要向大家介绍Rust中的workspace,主要内容包括基础应用、实用技巧、原理机制等方面,这个概念在Rust中是通用的,只不过maven换成了cargo,而模块变成了crate,下面跟着小编通过一个例子给大家介绍下
    2022-03-03
  • Rust调用Windows API 如何获取正在运行的全部进程信息

    Rust调用Windows API 如何获取正在运行的全部进程信息

    本文介绍了如何使用Rust调用WindowsAPI获取正在运行的全部进程信息,通过引入winapi依赖并添加相应的features,可以实现对不同API集的调用,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • Rust中字符串String集合的具有使用

    Rust中字符串String集合的具有使用

    在Rust中,字符串方法主要位于标准库的std::string模块中,这些方法可以帮助我们处理字符串的常见操作,本文主要介绍了Rust中字符串String集合的具有使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • Rust实现构建器模式和如何使用Bon库中的构建器

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

    这篇文章主要介绍了Rust实现构建器模式和如何使用Bon库中的构建器,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-08-08
  • 在win10上使用mingw64编译器配置Rust开发环境和idea 配置Rust 插件

    在win10上使用mingw64编译器配置Rust开发环境和idea 配置Rust 插件

    在win10上配置 Rust 开发环境(使用 mingw64编译器)和 idea 配置 Rust 插件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-03-03
  • 关于Rust 使用 dotenv 来设置环境变量的问题

    关于Rust 使用 dotenv 来设置环境变量的问题

    在项目中,我们通常需要设置一些环境变量,用来保存一些凭证或其它数据,这时我们可以使用dotenv这个crate,接下来通过本文给大家介绍Rust 使用dotenv来设置环境变量的问题,感兴趣的朋友一起看看吧
    2022-01-01
  • Rust 连接 SQLite 数据库的过程解析

    Rust 连接 SQLite 数据库的过程解析

    本文通过一个例子给大家介绍了Rust 连接 SQLite 数据库的详细过程,我使用rusqlite这个crate,对Rust 连接 SQLite 数据库相关知识感兴趣的朋友跟随小编一起看看吧
    2022-01-01
  • Rust语言之使用Polar权限管理方法详解

    Rust语言之使用Polar权限管理方法详解

    权限管理 (Permission Management) 是一个涵盖了系统或网络中用户权限控制和管理的系统,本文将详细给大家介绍Rust语言中如何使用Polar权限管理,需要的朋友可以参考下
    2023-11-11
  • Rust你不认识的所有权

    Rust你不认识的所有权

    所有权对大多数开发者而言是一个新颖的概念,它是 Rust 语言为高效使用内存而设计的语法机制。所有权概念是为了让 Rust 在编译阶段更有效地分析内存资源的有用性以实现内存管理而诞生的概念
    2023-01-01

最新评论