Rust练手项目1--minigrep

minigrep

官方教程断断续续看了10章,写个小demo练习下。目前感觉还行,继续看完再来重构一个版本。

目录结构

cargo.toml

toml 复制代码
[package]
name = "minigrep"
version = "0.0.1"
edition = "2024"

[dependencies]

grepp.txt

txt 复制代码
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!

main.rs

rust 复制代码
use std::env::args;

fn main() {
    let args: Vec<String> = args().collect();
    // 去掉第一个参数
    let params = &args[1..].to_vec();
    minigrep::grep(params);
}

lib.rs

rust 复制代码
use std::io::{Error};
use std::io::ErrorKind::InvalidInput;
use std::process;
use crate::common::status::Status;
pub mod common;

pub fn grep(params:&Vec<String>){
    check_params(&params);
    use common::content::Content;
    let result =  Content::parse(&params).search();
    if !result.is_empty(){
        println!("{:?}", result);
    }
}

/// 校验参数
fn check_params(params:&Vec<String>){
    // 检验长度
    let mut  status = check_params_len(params.len()).unwrap_or_else(out_err);
    if status.eq(&Status::Stop){
        process::exit(0);
    }
    // 检验合法
    status = check_params_invalid(params).unwrap_or_else(out_err);
    if status.eq(&Status::Stop){
        process::exit(0);
    }
}
fn check_params_len(len:usize) -> Result<Status,Error>{
    if len > 0 {
        return Ok(Status::Continue )
    }
    Err(Error::new(InvalidInput,"未指定有效参数 --help 可查看支持的参数!"))
}

fn check_params_invalid(params:&Vec<String>) -> Result<Status, Error>{
    use common::commands::Commands;
    let commands = Commands::values();
    for param in params {
        for command in &commands {
         if param.to_lowercase().starts_with(command.as_str()) {
             let display = command.display();
             if display.is_empty() {
                 return Ok(Status::Continue)
             }else {
                 println!("{}", display);
                 return Ok(Status::Stop )
             }
            }
        }
    }
    Ok(Status::Continue)
}

fn out_err(error:Error) -> Status{
    eprintln!("参数错误:{}", error);
    process::exit(1);
}

common/mod.rs

rust 复制代码
pub mod content;
pub mod commands;
pub mod status;

common/commands.rs

rust 复制代码
pub enum Commands {
    Help,
    Version,
    FilePath,
    LowerCase,
    Keyword,
}
impl Commands {
    pub fn as_str(&self) -> &str {
        use Commands::*;
        match *self {
            Help => "--help",
            Version => "--version",
            FilePath => "--filepath",
            LowerCase => "--lowercase",
            Keyword => "--keyword",
        }
    }
    pub fn values() -> Vec<Commands> {
        use Commands::*;
        vec![Help, Version, FilePath, LowerCase, Keyword]
    }

    pub fn display(&self) -> &str{
        use Commands::*;
        match *self {
            Help => "--help \t 帮助 \n \
            --version \t 版本 \n \
            --filepath=xxx.txt \t 文件路径 \n \
            --lowercase=false \t 是否忽略大小写 \n \
            --keyword=key \t 搜索关键词 \n",
            Version => "0.0.1",
            _ => "",
        }
    }
}

common/content.rs

rust 复制代码
use std::{fs, process};

pub struct Content{
    file_path: String, // 文件路径
    search_keyword:String, //搜索关键字
    context: String, // 文件内容
    lowercase:bool,//忽略大小写
}

impl Content {
   pub fn parse(params:&Vec<String>)->Content{
       let mut content = Content {
           file_path: "".to_string(),
           search_keyword: "".to_string(),
           context: "".to_string(),
           lowercase: true
       };
       for param in params {
           if param.to_lowercase().starts_with("--filepath="){
               content.file_path = param.replace("--filepath=", "");
           }
           if param.to_lowercase().starts_with("--keyword="){
               content.search_keyword = param.replace("--keyword=", "");
           }
           if param.to_lowercase().starts_with("--lowercase="){
               content.lowercase = param.replace("--lowercase=", "").parse().unwrap_or_default();
           }
       }
       if content.search_keyword.is_empty() {
           eprintln!("No search keyword specified");
           process::exit(1);
       }
       if !content.file_path.is_empty() {
           let result = fs::read_to_string(&content.file_path)
               .unwrap_or_else(|err| {
                   eprintln!("Error reading file: {}", err);
                   process::exit(1)
               });
           content.context = result.trim().to_string();
       }
       if content.context.is_empty() {
           eprintln!("No context specified");
           process::exit(1);
       }
       content
    }

    pub fn search(&self) -> Vec<String> {
        let mut resut = vec![];
        if self.context.is_empty() {
            vec![]
        }else {
            let mut key = self.search_keyword.clone();
            for line in self.context.lines() {
                if !line.is_empty() {
                    let mut context = line.to_string();
                    if self.lowercase{
                        context = line.to_string().to_lowercase();
                        key = key.to_lowercase();
                    }
                    if context.contains(&key) {
                        resut.push(context);
                    }
                }
            }
            resut
        }
    }
}

common/status.rs

rust 复制代码
#[derive(PartialEq)]
pub enum Status{
    Stop,
    Continue,
}

输出

相关推荐
穗余6 分钟前
Rust——什么是标量类型,isize / usize 是什么
rust
穗余24 分钟前
Rust——impl是什么意思
开发语言·后端·rust
代码羊羊27 分钟前
Rust模式匹配
开发语言·后端·rust
好家伙VCC4 小时前
**发散创新:用Rust实现基于RAFT共识算法的轻量级分布式日志系统**在分布式系统中,**一致性协议**是保障数据可靠
java·分布式·python·rust·共识算法
Amos_Web17 小时前
Solana 智能合约编译问题排查与修复总结
前端·rust·区块链
代码羊羊17 小时前
rust-字符串(切片)、元组、结构体、枚举、数组
开发语言·后端·rust
好家伙VCC19 小时前
**发散创新:用 Rust实现游戏日引擎核心模块——从事件驱动到多线程调度的实战
java·开发语言·python·游戏·rust
RFCEO1 天前
Rust编程基础课 第1课时:Rust简介与环境搭建 STM32 RUST嵌入式编程实战
stm32·嵌入式硬件·rust·probe-rs·rust工具链·rustup、cargo·stm32 rust适配