跳转至

Lab 3:用 Rust 重新实现 cut

作业内容

本题提供 GNU cut 的使用说明和 coreutils-9.11/src/cut.c 源码。你需要借助 Agent 阅读这些材料,并用 Rust 重新实现本题要求的功能。

不要逐句翻译

请按 Rust 常见的写法重新实现,可以自由使用 Vec、迭代器、Result 和标准库的字符串方法,不需要保持 C 版本的代码结构。

不要为了照搬 C 代码而使用裸指针或 unsafe

程序行为以 GNU coreutils 9.11 为准。

功能要求

cut 的作用

cut 是 GNU coreutils 中用于提取文本指定部分的工具。例如,文件 scores.txt 的内容是:

Alice:90
Bob:85

运行:

cut -d: -f2 scores.txt

会得到:

90
85

这里的 -d: 表示使用 : 分隔每一行,-f2 表示输出分隔后的第 2 个字段。字段从 1 开始编号。

OJ 输入

真实的 cut 从命令行接收 -d:-f2 等参数,再从文件或标准输入读取要处理的文本。OJ 只能向学生程序提供标准输入,不能为每组测试设置命令行参数,因此本题把两部分合并到一次输入中:

-d: -f2
Alice:90
Bob:85

学生程序需要按下面的方式读取:

  1. 第一行是 cut 的参数。本例要求用 : 分隔并输出第 2 个字段;
  2. 第二行开始是需要处理的文本。本例需要处理 Alice:90Bob:85
  3. 第一行不是待处理文本,不能出现在输出中。

第一行中的参数以空白字符分隔,不含引号和转义。选项和值可以连写,也可以分开写,例如 -f2-f 2 含义相同。程序必须从标准输入读取这些参数,不能使用 std::env::args()

参数

参数 功能
-f LIST 按字段选取
-d DELIM 指定字段分隔符,默认为制表符
-b LIST 按字节选取
-c LIST 按字符选取
-s 只输出含分隔符的行

LIST 的语法:

形式 含义
N 单个位置,从 1 开始编号
N-M 闭区间
N- 从 N 到行尾
-M 从行首到 M

可用逗号分隔多项,例如 1,3-5,8-

其他未提到的参数都不要求实现。

行为要求

以下几条是本题的重点,请确认你的实现全部满足。

  1. 使用 -f 时,若某行不含分隔符,整行原样输出;若同时指定了 -s,则跳过该行。
  2. 输出顺序按位置升序,与 LIST 中的书写顺序无关。例如对 a:b:c 执行 -d: -f3,1 得到 a:c,不是 c:a
  3. LIST 中的范围重叠时合并,不重复输出。例如对 a:b:c:d 执行 -d: -f1-2,2-3 得到 a:b:c
  4. 行首或行尾的分隔符会产生空字段,空字段同样参与编号。
  5. -b-c-f 三者互斥,同时指定应报错退出。
  6. LIST 为空或包含 0 应报错退出。
  7. -s 只在按字段操作时有意义,与 -b-c 同用应报错退出。
  8. 输入的数据部分只有一个空行时,仍应输出一个空行;数据部分完全为空时不输出。

错误处理只要求退出码非零,不要求错误信息与 GNU 版本逐字一致。

关于 -b-c-b 按字节计位置,可能切断多字节字符,输出的字节序列不一定是合法的 UTF-8;-c 按字符计位置。两者在纯 ASCII 数据上结果相同。

这几条大多不符合直觉

第 1、2、3 条尤其如此。它们是 cut 几十年来的实际行为,不是我们设计的陷阱。Agent 第一次生成的程序很容易在这些地方出错,请用后面介绍的方法逐一和 GNU cut 比较输出。

样例

输入:

-d: -f2
a:b:c
nodelim
:leading
trailing:

输出:

b
nodelim
leading

第二行不含分隔符,整行输出;第三行的第二个字段是 leading;第四行的第二个字段为空,因此输出空行。

下载材料

从课程文档仓库下载 lab3-materials-v1.zip。压缩包包含:

  • cut.c:GNU coreutils 9.11 的 src/cut.c
  • cut.1.txt:同版本 cut man page 的纯文本;
  • COPYINGSOURCE.txt:许可证与来源说明。

文件的 SHA-256 为:

671844c01da6ccf560966b96ee60331b0981f62ca9b1952bf56b5688ef1c370f

若 Release 暂时无法下载,也可以从 GNU 官方获取完整源码:

curl -O https://ftp.gnu.org/gnu/coreutils/coreutils-9.11.tar.xz

完整源码中的目标文件是 coreutils-9.11/src/cut.c。完成作业只需阅读附件中的两个文件,不需要编译整个 coreutils。

评测环境

本题以 GNU coreutils 9.11 的行为为准。标准答案已经提前生成;OJ 评分时只运行你提交的程序并比较输出,不会在评测环境中调用 cut

macOS 用户注意

macOS 自带的 /usr/bin/cut 不是本题采用的 GNU 版本。两者的许多常用功能相同,但不能保证所有边界情况完全一致。需要与本题采用的版本对比时,请用 Homebrew 安装 GNU coreutils:

brew install coreutils

安装后命令名是 gcut。请运行 gcut --version 检查版本;准备本题时 Homebrew 提供的是 GNU coreutils 9.11。比较输出时使用 gcut,不要把 macOS 自带的 cut 当作最终依据。

提交内容

  1. 在 OJ 上提交你的 .rs 文件
  2. 在网络学堂作业中上传一个或多个已经检查、并在必要时完成脱敏的 Session JSON

文件命名见环境配置

评分

项目 分值
五组数据(每组 0.4 分) 2.0
Session 文件完整 0.5
合计 2.5