当前位置: 首页 > news >正文

使用rust复刻linux经典命令:wc(文本统计工具)

文章目录

    • 一、项目概述
      • 项目简介
      • 核心功能
      • 技术栈
    • 二、项目结构
    • 三、各文件代码实现
      • Cargo.toml(项目配置)
      • src/counter.rs(统计器核心逻辑)
      • src/file_handler.rs(文件读取与统计)
      • src/main.rs(入口文件:参数解析与调度)
    • 四、使用指南
      • 基础命令(与原生 wc兼容)
      • 输出示例

一、项目概述

项目简介

基于 Rust 实现 Linux 经典工具wc(word count)的核心功能,支持统计文件的字节数、字符数、单词数和行数。保持与原生 wc命令的兼容性,同时利用 Rust 的安全性和高效性,实现跨平台支持(Windows/macOS/Linux)。

核心功能

  • 基础统计:行数(-l)、单词数(-w)、字节数(-c)、字符数(-m)
  • 多文件支持:同时统计多个文件,输出单个文件统计结果与总和
  • 默认模式:无参数时默认统计 行数 + 单词数 + 字节数(与原生wc一致)
  • 跨平台兼容:适配不同系统的换行符(\n/\r\n)和编码(默认 UTF-8)

技术栈

  • 开发语言:Rust(Edition 2021)
  • 核心依赖:clap(命令行参数解析)
  • 标准库模块:std::fs(文件读取)、std::io(流处理)、std::path::Path(路径处理)

二、项目结构

rust_wc/
├── Cargo.toml          # 项目配置与依赖
└── src/├── main.rs         # 入口文件:参数解析、调度统计逻辑├── counter.rs      # 核心逻辑:统计器实现(字节/字符/单词/行数)└── file_handler.rs # 文件处理:单文件读取与统计、多文件汇总

三、各文件代码实现

Cargo.toml(项目配置)

[package]name = "rust_wc"version = "0.1.0"edition = "2021"description = "Rust 实现的 wc 命令行工具"authors = ["Your Name"][dependencies]clap = { version = "4.4", features = ["derive"] } # 命令行参数解析

src/counter.rs(统计器核心逻辑)

/// 统计结果结构体(存储单个文件的统计数据)#[derive(Debug, Clone, Copy, Default)]pub struct CountResult {pub lines: u64,    // 行数pub words: u64,    // 单词数(以空白字符分隔)pub bytes: u64,    // 字节数pub chars: u64,    // 字符数(UTF-8 编码)}/// 统计器:处理字节流,累计统计结果pub struct WcCounter {result: CountResult,in_word: bool, // 标记是否处于单词中(用于单词数统计)}impl Default for WcCounter {fn default() -> Self {Self {result: CountResult::default(),in_word: false,}}}impl WcCounter {/// 创建新的统计器pub fn new() -> Self {Self::default()}/// 处理单个字节(更新字节数、行数、单词数)fn process_byte(&mut self, byte: u8) {// 字节数+1self.result.bytes += 1;// 行数统计:遇到 \n 则行数+1(兼容 Unix 换行符)if byte == b'\n' {self.result.lines += 1;}// 单词数统计:空白字符(空格/制表符/换行/回车)作为分隔符let is_whitespace = byte.is_ascii_whitespace();if !is_whitespace && !self.in_word {// 从非单词状态进入单词状态,单词数+1self.result.words += 1;self.in_word = true;} else if is_whitespace && self.in_word {// 从单词状态进入空白状态,标记退出单词self.in_word = false;}}/// 处理字符(更新字符数,仅在需要统计字符时调用)fn process_char(&mut self) {self.result.chars += 1;}/// 处理字节流(核心方法:逐字节处理,支持同时统计字节/行/单词;按需统计字符)pub fn process_stream<R: std::io::Read>(&mut self,mut reader: R,count_chars: bool, // 是否需要统计字符数) -> Result<(), Box<dyn std::error::Error>> {let mut buffer = [0u8; 1024]; // 1KB 缓冲区,提升读取效率while let Ok(n) = reader.read(&mut buffer) {if n == 0 {break; // 读取结束}// 处理缓冲区中的字节(统计字节/行/单词)for &byte in &buffer[..n] {self.process_byte(byte);}// 如需统计字符数:将缓冲区解析为 UTF-8 字符if count_chars {let s = std::str::from_utf8(&buffer[..n])?;for _ in s.chars() {self.process_char();}}}Ok(())}/// 获取最终统计结果pub fn get_result(&self) -> CountResult {self.result}}/// 汇总多个文件的统计结果pub fn sum_results(results: &[CountResult]) -> CountResult {results.iter().fold(CountResult::default(), |mut sum, res| {sum.lines += res.lines;sum.words += res.words;sum.bytes += res.bytes;sum.chars += res.chars;sum})}

src/file_handler.rs(文件读取与统计)

use std::fs::File;use std::path::Path;use crate::counter::{WcCounter, CountResult};/// 统计单个文件的核心逻辑/// - path: 文件路径/// - count_lines: 是否统计行数/// - count_words: 是否统计单词数/// - count_bytes: 是否统计字节数/// - count_chars: 是否统计字符数pub fn count_file(path: &Path,count_lines: bool,count_words: bool,count_bytes: bool,count_chars: bool,) -> Result<CountResult, Box<dyn std::error::Error>> {let file = File::open(path)?;let mut counter = WcCounter::new();// 仅在需要统计字符时传递 true(避免不必要的 UTF-8 解析开销)counter.process_stream(file, count_chars)?;Ok(counter.get_result())}/// 处理多个文件统计:输出单个文件结果 + 汇总结果pub fn count_multiple_files(paths: &[impl AsRef<Path>],count_lines: bool,count_words: bool,count_bytes: bool,count_chars: bool,) -> Result<(), Box<dyn std::error::Error>> {let mut all_results = Vec::with_capacity(paths.len());// 统计每个文件并输出结果for path in paths {let path = path.as_ref();let result = count_file(path, count_lines, count_words, count_bytes, count_chars)?;print_result(&result, path.file_name().unwrap().to_string_lossy(), count_lines, count_words, count_bytes, count_chars);all_results.push(result);}// 输出汇总结果(多文件时)if paths.len() > 1 {let total = crate::counter::sum_results(&all_results);print_result(&total, "total", count_lines, count_words, count_bytes, count_chars);}Ok(())}/// 格式化输出统计结果(对齐格式,与原生 wc 保持一致)fn print_result(result: &CountResult,filename: impl std::fmt::Display,count_lines: bool,count_words: bool,count_bytes: bool,count_chars: bool,) {let mut parts = Vec::new();// 按原生 wc 顺序:行数 → 单词数 → 字符数 → 字节数if count_lines {parts.push(format!("{:>8}", result.lines)); // 右对齐,占 8 字符}if count_words {parts.push(format!("{:>8}", result.words));}if count_chars {parts.push(format!("{:>8}", result.chars));}if count_bytes {parts.push(format!("{:>8}", result.bytes));}// 拼接结果 + 文件名println!("{}  {}", parts.join(""), filename);}

src/main.rs(入口文件:参数解析与调度)

use clap::Parser;use std::path::Path;use crate::file_handler::{count_file, count_multiple_files};/// Rust 实现的 wc 命令(统计文件的行数、单词数、字节数、字符数)#[derive(Parser, Debug)]#[command(author, version, about, long_about = None)]struct Cli {/// 统计行数#[arg(short = 'l', long = "lines")]lines: bool,/// 统计单词数(以空白字符分隔)#[arg(short = 'w', long = "words")]words: bool,/// 统计字节数#[arg(short = 'c', long = "bytes")]bytes: bool,/// 统计字符数(UTF-8 编码)#[arg(short = 'm', long = "chars")]chars: bool,/// 要统计的文件路径(支持多个文件)#[arg(default_value = "-")] // 默认读取标准输入(与原生 wc 一致)files: Vec<String>,}fn main() -> Result<(), Box<dyn std::error::Error>> {let cli = Cli::parse();// 确定需要统计的维度:无参数时默认 行数+单词数+字节数let count_lines = cli.lines || !(cli.words || cli.bytes || cli.chars);let count_words = cli.words || !(cli.lines || cli.bytes || cli.chars);let count_bytes = cli.bytes || !(cli.lines || cli.words || cli.chars);let count_chars = cli.chars;// 处理标准输入(文件路径为 "-" 时)if cli.files == vec!["-".to_string()] {let mut counter = crate::counter::WcCounter::new();// 从标准输入读取流counter.process_stream(std::io::stdin(), count_chars)?;let result = counter.get_result();// 输出结果(无文件名)let mut parts = Vec::new();if count_lines { parts.push(format!("{:>8}", result.lines)); }if count_words { parts.push(format!("{:>8}", result.words)); }if count_chars { parts.push(format!("{:>8}", result.chars)); }if count_bytes { parts.push(format!("{:>8}", result.bytes)); }println!("{}", parts.join(""));return Ok(());}// 处理文件(转换为 Path 类型,过滤无效路径)let paths: Vec<_> = cli.files.iter().map(|s| Path::new(s)).collect();// 多文件统计(含单个文件)count_multiple_files(&paths, count_lines, count_words, count_bytes, count_chars)?;Ok(())}// 导入子模块mod counter;mod file_handler;

四、使用指南

基础命令(与原生 wc兼容)

# 编译项目cargo build --release# 进入编译产物目录(可选,方便直接执行)cd target/release# 1. 默认模式:统计行数+单词数+字节数(单个文件)
./rust_wc test.txt# 2. 统计行数(-l)
./rust_wc -l test.txt# 3. 统计单词数(-w)
./rust_wc -w test.txt# 4. 统计字节数(-c)
./rust_wc -c test.txt# 5. 统计字符数(-m,UTF-8 编码)
./rust_wc -m test.txt# 6. 组合统计(行数+字符数)
./rust_wc -l -m test.txt# 7. 多文件统计(自动输出总和)
./rust_wc test1.txt test2.txt# 8. 读取标准输入(管道使用)echo "Hello Rust" | ./rust_wc
cat test.txt | ./rust_wc -l

输出示例

# 单个文件默认模式
./rust_wc test.txt12      45     320 test.txt  # 行数 单词数 字节数 文件名# 多文件统计(含总和)

这个项目保持与原生 wc 命令的参数格式和输出格式一致,降低使用成本,非常不错

想了解更多关于Rust语言的知识及应用,可前往华为开放原子旋武开源社区(https://xuanwu.openatom.cn/),了解更多资讯~

http://www.dtcms.com/a/617595.html

相关文章:

  • 网站设计公司哪里好镇江网站建设找思创网络
  • 45_FastMCP 2.x 中文文档之FastMCP集成:Azure (Entra ID) 指南
  • 【微服务中间件】RabbitMQ 全方位解析:同步异步对比、SpringAMQT基础入门、实战、交换机类型及消息处理详解
  • 单点高ROI场景医疗AI编程分析与实践
  • 使用python进行PostgreSQL 数据库连接
  • 天线类型和指标介绍
  • Netty编写Echo服务器
  • 沙雕图片视频制作软件。制图内都是搞笔图制作模板,表白墙,节日祝福制作
  • 开源项目分享 图像深度学习Demo项目
  • 性能优化方向
  • 2.socket套接字
  • 旧网站如何优化设计制作实践活动有哪些
  • HTML 实例详解
  • 【监控】Spring Boot+Prometheus+Grafana实现可视化监控
  • 【深度学习新浪潮】大模型在图像质量评价方面的研发进展一览
  • **MATLAB R2025a** 环境下,基于 **双向时间卷积网络(BITCN)+ 双向长短期记忆网络(BiLSTM)** 的多特征分类预测完整实现
  • 在21世纪的我用C语言探寻世界本质——字符函数和字符串函数(2)
  • 《基于机器学习的脑电认知负荷识别研究与应用》论文笔记
  • 数据结构:双向链表(2)
  • Java EE - 常见的死锁和解决方法
  • transformer 教程(一) qkv矩阵介绍以及为什么除以根号d推导
  • 网络网站开发江苏电信网站备案
  • 树莓派 5 上 Ubuntu 24.04 LTS 自带 RDP 远程桌面重启密码就变
  • 算法---贪心算法(Greedy Algorithm)
  • TDengine 字符串函数 REGEXP_IN_SET 用户手册
  • 佛山市外贸网站建设公司因网站开发需要
  • 神经网络组植物分类学习规划与本周进展综述15
  • 做律师事务所网站牡丹江住房和城乡建设厅网站
  • 上海崇明林业建设有限公司 网站建设 市民中心网站
  • 在UEC++中使用什么方式返回像 FTransform 这种类型的值