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,
}

输出

相关推荐
yume_sibai27 分钟前
11-Rust 不安全编程(unsafe 关键字 + 裸指针 + FFI + 内联汇编 + 内存安全保证)
汇编·安全·rust
Leaderxin3 小时前
还在用 Electron?6 种跨平台桌面方案横评:Rust + Vue 把安装包从 224MB 干到 4.7MB
rust·vue·跨平台·tauri·桌面应用
海盗12343 小时前
微软技术日报 2026-09-14:Rust 升为微软一级语言,云业务重组为智能体与基础设施
开发语言·microsoft·rust
传奇开心果编程3 小时前
【xilem0.4基础语法学与练】第53课 to_do_mvc 官方示例代码深度解析
学习·rust·前端框架
孙启超3 小时前
【AI开发之Rust】第 5 课:引用与生命周期 —— 借用能活多久?
人工智能·后端·rust·llm·ai应用开发
喵喵锤锤你小可爱4 小时前
SerialHub:把串口变成 WebSocket 字节管道,浏览器和脚本直接读写(开源工具 SerialHub 实战)
websocket·rust·嵌入式·串口调试·开源工具
传奇开心果编程5 小时前
【xilem0.4基础语法学与练】第48课 lists组件官方示例代码深度解析
学习·rust·前端框架
传奇开心果编程9 小时前
【Rust入门知识点学与练】第24课:Trait 基础
开发语言·学习·rust
传奇开心果编程1 天前
【dioxus0.7基础语法学与练】第8课:RSX 宏 — Dioxus 声明式 UI 语法
开发语言·学习·rust
柯南46681 天前
【AI开发之Rust】第 5 课:引用与生命周期 —— 借用能活多久?
rust