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

输出

相关推荐
Rust语言中文社区17 小时前
【Rust日报】 Danube Messaging - 云原生消息平台
开发语言·后端·rust
Rust研习社20 小时前
构建可扩展 Rust 项目:从模块化到 Workspace 工程化实践
rust
好家伙VCC20 小时前
**发散创新:用 Rust实现数据编织(DataWrangling)的高效流式处理架构**在现
java·开发语言·python·架构·rust
本地化文档1 天前
rustdoc-book-l10n
rust·github·gitcode
Tony Bai1 天前
Rust 看了流泪,AI 看了沉默:扒开 Go 泛型最让你抓狂的“残疾”类型推断
开发语言·人工智能·后端·golang·rust
jump_jump2 天前
RTK:给 AI 编码助手瘦身的 Rust 代理
性能优化·rust·claude
小杍随笔2 天前
【Rust Exercism 练习详解:Anagram + Space Age + Sublist(附完整代码与深度解读)】
开发语言·rust·c#
Rust研习社2 天前
Rust 字符串与切片实战
rust
朝阳5812 天前
局域网聊天工具
javascript·rust
朝阳5812 天前
我做了一个局域网传文件的小工具,记录一下
javascript·rust