Rust Simple Grep

一个用 Rust 实现的简单的 grep,可以读取文件,匹配正则表达式。

代码思路: 使用 regex 正则表达式库,env 读取 args 命令行参数。第1个参数为文件,第2个参数为正则表达式。

将正则表达式匹配到的行输出,并高亮匹配到的内容。同时显示所在行数。

如果没有第二个正则表达式参数,直接输出文件内容。

最后显示找的几行,几个符合正则表达式的字符串。

Cargo.toml

1
2
3
4
5
6
7
8
9
[package]
name = "mygrep"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
regex = "1.5.5"

src/main.rs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use regex::Regex;
use std::env;
use std::fs::File;
use std::io::Read;
fn main() {
    // ["D:\\rustcode\\grep\\target\\debug\\grep.exe", "1", "2", "3"]
    let args: Vec<String> = env::args().collect();
    let file_path = args.get(1);
    let regex = args.get(2);
    let ex = args.get(3);
    if ex.is_some() {
        red("Extra words will be ingroned!");
    }
    match file_path {
        Some(path) => read_file(path, regex),
        None => {
            red("No file path provided");
            green("Helper:\nmygrep <file_path> <regex>");
        }
    }
}
fn read_file(file_path: &str, regex: Option<&String>) {
    let file = File::open(file_path);
    match file {
        Ok(mut file) => {
            green(&format!("Reading {}", file_path));
            let mut contents = String::new();
            let mut sum_lines = 0;
            let mut sum_key = 0;
            file.read_to_string(&mut contents).unwrap();
            match regex {
                Some(regex) => {
                    let re = Regex::new(&regex.to_string()).unwrap();
                    let mut lines = contents.lines();
                    let mut k = 1;
                    while let Some(line) = lines.next() {
                        if re.is_match(line) {
                            let mut ans = line.to_string();
                            for caps in re.captures_iter(line) {
                                let from = caps.get(0).unwrap().as_str();
                                ans = ans.replace(from.clone(), &blue(from));
                                sum_key += 1;
                                //    println!("CAPS: {:?}", caps.get(0).unwrap().as_str());
                            }
                            sum_lines += 1;
                            println!("{}: {}", yellow(&k.to_string()), ans);
                        }
                        k += 1;
                    }
                }
                None => {
                    let mut k = 1;
                    //  println!("{}", contents);
                    contents.lines().for_each(|line| {
                        println!("{}: {}", yellow(&k.to_string()), line);
                        k += 1;
                    });
                }
            }
            green(&format!("Found {} lines, Key nums: {}", sum_lines, sum_key));
        }
        Err(e) => panic!("File Open Error: {}", e),
    }
    //  println!("read {:?}", file_path);
}
fn red(msg: &str) {
    println!("\x1b[91m{}\x1b[0m", msg);
}
fn green(msg: &str) {
    println!("\x1b[92m{}\x1b[0m", msg);
}
fn yellow(msg: &str) -> String {
    format!("\x1b[93m{}\x1b[0m", msg)
}
fn blue(msg: &str) -> String {
    format!("\x1b[94m{}\x1b[0m", msg)
}

没有进行单元测试,异常也是直接抛出。对这个程序影响不是很大。

test.txt

1
2
3
4
read
bluetooth
blur old false
bluetooth bluetooth bluetoothbluetooth
https://cdn.ftls.xyz/images/2022/04/Snipaste_2022-04-11_09-12-00.png
text.txt测试

将 grep 路径加入操作系统的环境变量,然后就可以在终端中正常使用了。下面测试正则表达式的支持情况。

测试文件: https://www.ftls.xyz/posts/eshaas/index.md
结果:

https://cdn.ftls.xyz/images/2022/04/Snipaste_2022-04-11_09-09-12.png
正则表达式匹配和显示