首頁 > 軟體

Rust實現grep命令列工具的方法

2022-07-26 18:03:15

一、功能:

1、輸入要查詢的字串檔名,輸出所有匹配的行的內容

2、如果設定環境變數IGNORE_CASE,則grep匹配將忽略大小寫

3、可使用 > 符號來重定向標準輸出到指定檔案中

二、介紹

2.1 使用到的知識:

  • 讀取命令列引數
  • 讀取檔案內容
  • 錯誤處理
  • Test Driven Development(TDD)
  • 使用環境變數控制不同行為

2.2 程式碼

1、main.rs

use std::env;
use std::process;
use minigrep::Config;
fn main() {
    // let args: Vec<String> = env::args().collect();
    // let query = &args[1];
    // let filename = &args[2];

    // let content = fs::read_to_string(filename).expect("You have a problem in read a file");
    // println!("Filename: {}", filename);
    // println!("File content:n{}", content);

    //refactoring after
    let args: Vec<String> = env::args().collect();
    // let config = Config::new(&args);
    let config = Config::new(&args).unwrap_or_else(|err| {
        eprintln!("Problem parse arguments: {}", err);
        process::exit(1);
    });
    println!("query: {}, filename: {}", config.query, config.filename);
    
    if let Err(e) = minigrep::run(config) {
        eprintln!("Application Error: {}", e);
        process::exit(1);
    }
}

2、lib.rs

use std::error::Error;
use std::fs;
use std::env;
pub struct Config {
    pub query: String,
    pub filename: String,
    pub ignore_case: bool,
}
impl Config {
    // fn new(args: &[String]) -> Config {
    //     let query = args[1].clone();
    //     let filename = args[2].clone();
    //     Config {query, filename}
    // }
    pub fn new(args: &[String]) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("No enough arguments");
        }
        let query = args[1].clone();
        let filename = args[2].clone();
        let ignore_case = env::var("IGNORE_CASE").is_ok();
        Ok(Config{query, filename, ignore_case})
    }
}
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let content = fs::read_to_string(config.filename)?;
    // println!("With text:n{}", content);
    let result = if config.ignore_case {
        search_case_insensitive(&config.query, &content)
    } else {
        search(&config.query, &content)
    };
        for line in result {
            println!("{}", line);
    }
    Ok(())
}

pub fn search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    let mut result = Vec::new();
    for line in content.lines() {
        if line.contains(query) {
            result.push(line);
        }
    }
    result
}

pub fn search_case_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    let mut result = Vec::new();
    let query = query.to_lowercase();
    for line in content.lines() {
        if line.to_lowercase().contains(&query) {
            result.push(line);
        }
    }
    result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_result() {
        let query = "xwp";
        let content = "
Hello,rust!
xwp is handsome
You know!";
        assert_eq!(vec!["xwp is handsome"], search(query, content));
    }

    #[test]
    fn case_insensitive() {
        let query = "xWp";
        let content = "
Hello,rust!
xwp is handsome
You KonW";
        assert_eq!(vec!["xwp is handsome"], search_case_insensitive(query, content));
    }
}

三、使用

  • 需要輸入兩個引數,第一個是query,第二個是filename,如果引數少於兩個會報錯。
  • 如:cargo run xwp xwphs.txt,xwp是要查詢的內容,xwphs.txt是檔案。
  • minigrep預設是大小寫敏感的,可通過設定IGNORE_CASE環境變數,使得查詢忽略大小寫。

在powershell中設定臨時環境變數如:$Env:IGNORE_CASE=1,解除:Remove-Item Env:IGNORE_CASE;在shell中直接:將IGNORE_CASE=1放在最開始

引數不足時,提示Problem parse arguments: No enough argumentss

設定環境變數後,不區分大小寫,查詢到了資訊

到此這篇關於Rust實現grep命令列工具的文章就介紹到這了,更多相關Rust命令列工具內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com