"首次提交"
This commit is contained in:
1
minigrep_iterator/.gitignore
vendored
Executable file
1
minigrep_iterator/.gitignore
vendored
Executable file
@ -0,0 +1 @@
|
||||
/target
|
8
minigrep_iterator/Cargo.toml
Executable file
8
minigrep_iterator/Cargo.toml
Executable file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
132
minigrep_iterator/src/lib.rs
Executable file
132
minigrep_iterator/src/lib.rs
Executable file
@ -0,0 +1,132 @@
|
||||
//! mini grep
|
||||
//! 实现一个简易版本的grep工具的功能,通过传入要查询的字符串和文件名,会遍历每一行文件内容并将其输出到终端
|
||||
//!
|
||||
//! ***注意***
|
||||
//! 可通过 CASE_SENSITIVE 环境变量来进行设定是否忽略大小写进行匹配。
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
pub struct Config {
|
||||
/// 需要查询的字符串
|
||||
pub query: String,
|
||||
/// 检索字符串的文件名
|
||||
pub filename: String,
|
||||
/// 是否大小写敏感
|
||||
/// - true: 大小写敏感
|
||||
/// - false: 忽略大小写
|
||||
pub sensitive: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Config 的构造函数,传入一个string的iter,会将其构造为一个Config并返回,如果失败则返回一个Err并带有说明的字符串
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use minigrep::Config;
|
||||
/// let mut args = vec![String::from("to"), String::from("test.txt")];
|
||||
/// let cfg = Config::new(args.into_iter()).unwrap();
|
||||
/// assert_eq!(cfg.query, "to");
|
||||
/// assert_eq!(cfg.filename, "test.txt");
|
||||
/// ```
|
||||
pub fn new<T>(mut args: T) -> Result<Config, &'static str>
|
||||
where
|
||||
T: Iterator<Item = String>,
|
||||
{
|
||||
let query = args.next().unwrap();
|
||||
let filename = args.next().unwrap();
|
||||
let sensitive = std::env::var("CASE_SENSITIVE").is_ok();
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GrepRet {
|
||||
line: i32,
|
||||
context: String,
|
||||
}
|
||||
impl GrepRet {
|
||||
fn new(line: i32, context: &str) -> GrepRet {
|
||||
GrepRet {
|
||||
line,
|
||||
context: context.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Display for GrepRet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "line:{}: {}", self.line, self.context)
|
||||
}
|
||||
}
|
||||
/// 字符串匹配的实操入口函数,
|
||||
/// - 入参:<br>
|
||||
/// Config
|
||||
/// - 返回值:<br>
|
||||
/// 查询到的匹配字串的文本行以及行号,如果发生错误则返回Err
|
||||
pub fn run(config: &Config) -> Result<Vec<GrepRet>, Box<dyn Error>> {
|
||||
let context = std::fs::read_to_string(&config.filename)?;
|
||||
if config.sensitive {
|
||||
Ok(search_sensitive(&config.query, &context))
|
||||
} else {
|
||||
Ok(search_insensitive(&config.query, &context))
|
||||
}
|
||||
}
|
||||
|
||||
fn search_sensitive(query: &str, context: &String) -> Vec<GrepRet> {
|
||||
let mut idx = 0;
|
||||
let mut result = Vec::new();
|
||||
for line in context.lines() {
|
||||
idx += 1;
|
||||
if line.contains(query) {
|
||||
result.push(GrepRet::new(idx, line));
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn search_insensitive(query: &str, context: &String) -> Vec<GrepRet> {
|
||||
let mut idx = 0;
|
||||
let mut result = Vec::new();
|
||||
for line in context.lines() {
|
||||
idx += 1;
|
||||
let lower = line.to_lowercase();
|
||||
if lower.contains(&query.to_lowercase()) {
|
||||
result.push(GrepRet::new(idx, line));
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn grep_new1() {
|
||||
let line = 10;
|
||||
let context = "zzz";
|
||||
let grep_ret = GrepRet::new(line, context);
|
||||
assert_eq!(line, grep_ret.line);
|
||||
assert_eq!(context, grep_ret.context);
|
||||
}
|
||||
#[test]
|
||||
fn grep_new2() {
|
||||
let line = 10;
|
||||
let context = "zzz";
|
||||
let grep_ret = GrepRet::new(line, context);
|
||||
assert_ne!(!line, grep_ret.line);
|
||||
assert_eq!(context, grep_ret.context);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // cargo test -- --ignored
|
||||
fn grep_new3() {
|
||||
let line = 10;
|
||||
let context = "zzz";
|
||||
let grep_ret = GrepRet::new(line, context);
|
||||
assert_ne!(!line, grep_ret.line);
|
||||
assert_eq!(context, grep_ret.context);
|
||||
}
|
||||
}
|
25
minigrep_iterator/src/main.rs
Executable file
25
minigrep_iterator/src/main.rs
Executable file
@ -0,0 +1,25 @@
|
||||
use std::env;
|
||||
use std::process;
|
||||
|
||||
use minigrep;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() < 3 {
|
||||
eprintln!("Usage: {} <text> <input file>", &args[0]);
|
||||
return;
|
||||
}
|
||||
let args1 = args.into_iter().skip(1);
|
||||
let config = minigrep::Config::new(args1).unwrap_or_else(|err| {
|
||||
println!("Problem: {}", err);
|
||||
process::exit(-1);
|
||||
});
|
||||
let result = minigrep::run(&config).unwrap_or_else(|err| {
|
||||
println!("Problem: {}", err);
|
||||
process::exit(-1);
|
||||
});
|
||||
println!("find {} in {}, is:", config.query, config.filename);
|
||||
for it in result {
|
||||
println!("{}", it);
|
||||
}
|
||||
}
|
9
minigrep_iterator/test.txt
Executable file
9
minigrep_iterator/test.txt
Executable file
@ -0,0 +1,9 @@
|
||||
ekko.bao
|
||||
emma.wang
|
||||
wwww
|
||||
to
|
||||
rust
|
||||
rust
|
||||
today is a nice day
|
||||
to you beast
|
||||
EKKO
|
Reference in New Issue
Block a user