如何基于Rust實(shí)現(xiàn)文本搜索minigrep
在Rust學(xué)習(xí)社區(qū)看到了 用Rust語(yǔ)言實(shí)現(xiàn)的minigrep,對(duì)于初學(xué)者的我來(lái)說(shuō),這個(gè)項(xiàng)目很感興趣,于是跟著實(shí)現(xiàn)了一遍,并完善了一點(diǎn)邏輯,以下是對(duì)項(xiàng)目的介紹
效果展示
本次演示介紹針對(duì)原作者代碼程序的查詢邏輯做了一點(diǎn)點(diǎn)小的優(yōu)化,原程序邏輯的查詢是放在了程序運(yùn)行的時(shí)候,邏輯修改后啟動(dòng)的時(shí)候可以添加參數(shù),也可以啟動(dòng)后添加,具體如下
修改前
查詢時(shí) 需要輸入查詢的字符串和文件cargo run -- th poem.txt
修改后
啟動(dòng)程序:cargo run輸入要查詢的字符串 th輸入要查詢的文件路徑 poem.txt查詢到的結(jié)果:
Then there’s a pair of us - don’t tell!
They’d banish us, you know.
To tell your name the livelong day退出程序:輸入:q
如下圖所示

代碼實(shí)現(xiàn)
代碼結(jié)構(gòu)
minigrep
├── Cargo.lock
├── Cargo.toml
├── output.txt
├── poem.txt
├── src
├── lib.rs
└── main.rs代碼展示
/src/main.rs
use std::{env, process};
use std::io::stdin;
use minigrep::Config;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 1 {
// 如果沒(méi)輸入查詢參數(shù),就循環(huán)等待用戶的輸入
loop {
println!("請(qǐng)輸入要查詢的字符串:");
// 等待用戶輸入
let mut input = String::new();
stdin().read_line(&mut input).expect("無(wú)法讀取");
let mut args = input.split_whitespace();
let mut a = String::new();
let query = args.next().unwrap_or_else(|| {
println!("請(qǐng)輸入有效的查詢字符串");
stdin().read_line(&mut a);
&a.as_str().trim()
});
if(":q".eq(query.clone())){
println!("程序退出");
process::exit(1);
}
let mut a = String::new();
let file_path = args.next().unwrap_or_else(|| {
println!("請(qǐng)輸入文件路徑:");
stdin().read_line(&mut a);
&a.as_str().trim()
});
let config1 = Config { query: query.to_string(), file_path: file_path.to_string(), ignore_case: true };
if let Err(e) = minigrep::run(config1) {
eprintln!("程序出錯(cuò):{e}");
}
}
} else {
// 啟動(dòng)時(shí)的入?yún)?
let config = Config::build(env::args()).unwrap_or_else(|err| {
eprintln!("程序解析 參數(shù)異常 {err}");
process::exit(1);
});
println!("search for {}", config.query);
println!("in file {}", config.file_path);
if let Err(e) = minigrep::run(config) {
eprintln!("程序出錯(cuò):{e}");
process::exit(1);
}
}
}/src/lib.rs
use std::error::Error;
use std::{env, fs};
// 查詢業(yè)務(wù)邏輯
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
if let Ok(contents) = fs::read_to_string(config.file_path){
let lines = if config.ignore_case {
search_case_insensitive(&config.query, &contents)
} else {
search(&config.query, &contents)
};
println!("查詢到的結(jié)果:");
for line in lines {
println!("{line}")
}
Ok(())
}else {
Err(Box::from("未查詢到文件"))
}
}
// 配置實(shí)體
pub struct Config {
pub query: String,
pub file_path: String,
pub ignore_case:bool,
}
impl Config {
// 構(gòu)建配置實(shí)體
pub fn build(mut args: impl Iterator<Item =String>) -> Result<Config, &'static str> {
let _programeName = args.next();
let query = match args.next() {
Some(query) => query,
None => return Err("未獲取到 要查詢的 字符串參數(shù)"),
};
let file_path = match args.next() {
Some(file_path) => file_path,
None => return Err("未獲取到文件路徑"),
};
// 從環(huán)境變量中找到是否包含 IGNORE_CASE
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config { query, file_path ,ignore_case})
}
}
// 對(duì)參數(shù)解析
fn parse_config(args: &[String]) -> Config {
let query = args[1].clone();
let file_path = args[2].clone();
let ignore_case = env::var("IGNORE_CASE").is_ok();
Config { query, file_path ,ignore_case}
}
// 大小寫(xiě)敏感查詢
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.contains(query))
.collect()
}
// 忽略大小寫(xiě)查詢
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
.collect()
}
// 測(cè)試模塊
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_result() {
let query = "duct";
let contents = "\
Rust:
safe, fast, productive.
Pick three.";
assert_eq!(vec!["safe, fast, productive."], search(query, contents))
}
#[test]
fn test_case_insensitive() {
let query = "RusT";
let contents = "\
Rust:
safe, fast, productive.
Pick three.";
assert_eq!(vec!["Rust:"], search_case_insensitive(query, contents))
}
}到此這篇關(guān)于基于Rust實(shí)現(xiàn)的文本搜索minigrep的文章就介紹到這了,更多相關(guān)Rust 文本搜索minigrep內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Rust中編寫(xiě)自定義Error的詳細(xì)代碼
Result<T, E> 類型可以方便地用于錯(cuò)誤傳導(dǎo),Result<T, E>是模板類型,實(shí)例化后可以是各種類型,但 Rust 要求傳導(dǎo)的 Result 中的 E 是相同類型的,所以我們需要編寫(xiě)自己的 Error 類型,本文給大家介紹了在Rust中編寫(xiě)自定義Error的詳細(xì)代碼,需要的朋友可以參考下2024-01-01
Rust調(diào)用Windows API 如何獲取正在運(yùn)行的全部進(jìn)程信息
本文介紹了如何使用Rust調(diào)用WindowsAPI獲取正在運(yùn)行的全部進(jìn)程信息,通過(guò)引入winapi依賴并添加相應(yīng)的features,可以實(shí)現(xiàn)對(duì)不同API集的調(diào)用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-11-11
Rust實(shí)現(xiàn)構(gòu)建器模式和如何使用Bon庫(kù)中的構(gòu)建器
這篇文章主要介紹了Rust實(shí)現(xiàn)構(gòu)建器模式和如何使用Bon庫(kù)中的構(gòu)建器,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
在win10上使用mingw64編譯器配置Rust開(kāi)發(fā)環(huán)境和idea 配置Rust 插件
在win10上配置 Rust 開(kāi)發(fā)環(huán)境(使用 mingw64編譯器)和 idea 配置 Rust 插件的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-03-03
關(guān)于Rust?使用?dotenv?來(lái)設(shè)置環(huán)境變量的問(wèn)題
在項(xiàng)目中,我們通常需要設(shè)置一些環(huán)境變量,用來(lái)保存一些憑證或其它數(shù)據(jù),這時(shí)我們可以使用dotenv這個(gè)crate,接下來(lái)通過(guò)本文給大家介紹Rust?使用dotenv來(lái)設(shè)置環(huán)境變量的問(wèn)題,感興趣的朋友一起看看吧2022-01-01
Rust 連接 SQLite 數(shù)據(jù)庫(kù)的過(guò)程解析
本文通過(guò)一個(gè)例子給大家介紹了Rust 連接 SQLite 數(shù)據(jù)庫(kù)的詳細(xì)過(guò)程,我使用rusqlite這個(gè)crate,對(duì)Rust 連接 SQLite 數(shù)據(jù)庫(kù)相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2022-01-01
Rust語(yǔ)言之使用Polar權(quán)限管理方法詳解
權(quán)限管理 (Permission Management) 是一個(gè)涵蓋了系統(tǒng)或網(wǎng)絡(luò)中用戶權(quán)限控制和管理的系統(tǒng),本文將詳細(xì)給大家介紹Rust語(yǔ)言中如何使用Polar權(quán)限管理,需要的朋友可以參考下2023-11-11

