跳转到内容

Rust 新手程序员指南/CSV 程序/CSV 文件和解析

来自维基教科书,开放的书籍,开放的世界

添加 CSV 文件和解析

[编辑 | 编辑源代码]

好的,让我们再次使用 'cargo new csv-program' 创建一个新的 cargo 程序。

对于我们的测试 csv 文件,我们将使用这个简单的字母频率 csv 文件

"Letter","Frequency","Percentage"
"A",24373121,8.1
"B",4762938,1.6
"C",8982417,3.0
"D",10805580,3.6
"E",37907119,12.6
"F",7486889,2.5
"G",5143059,1.7
"H",18058207,6.0
"I",21820970,7.3
"J",474021,0.2
"K",1720909,0.6
"L",11730498,3.9
"M",7391366,2.5
"N",21402466,7.1
"O",23215532,7.7
"P",5719422,1.9
"Q",297237,0.1
"R",17897352,5.9
"S",19059775,6.3
"T",28691274,9.5
"U",8022379,2.7
"V",2835696,0.9
"W",6505294,2.2
"X",562732,0.2
"Y",5910495,2.0
"Z",93172,0.0

只需将此复制并粘贴到项目根目录下的一个新文件中,即直接在 csv-program 下,名为 'letter_frequency.csv'。然后我们可以开始编码。

首先,我们将用 Rust 将文件读入字符串。为此,我们可以使用非常方便的函数 std::fs::read_to_string。 再次,我们将 'use std::fs;' 以便在调用函数时更加方便。

use std::fs;
fn main() {
    let csv_file = fs::read_to_string("letter_frequency.csv").unwrap();
   
    println!("{}", csv_file);
}

如果我们运行它,我们应该看到文件内容被打印到终端!

现在我们想逐行解析文件。第一行应该以不同的方式处理,因为它应该是文件标题。为此,我们可以使用 str 上的 lines() 函数。 这给了我们一个迭代器,但我们需要学习迭代器的基础知识才能将其用于我们想要的东西。

迭代器的工作原理
[编辑 | 编辑源代码]

迭代器是一个实现了 'Iter' 特征的结构体。这个特征只要求结构体具有以下函数

fn next(&mut self) -> Option<Self::Item>;

所有其他行为都可以从此函数推导出。关于此函数值得注意的是,它需要结构体的可变引用,这意味着一旦迭代器使用过一次,它就被用完了,不能再使用。另一个值得注意的事情是,它返回一个迭代器类型的 Option,这就是我们如何知道它是否完成的方式;如果迭代器还有剩余项目,它会返回 Some() 的项目,如果迭代器已完成,则返回 None。

因此,我们可以这样做来获取第一行

fn main() {
     let csv_file = fs::read_to_string("letter_frequency.csv").unwrap();
     
     let mut lines_iter = csv_file.lines();
     let first_line = lines_iter.next().unwrap();
     for line in lines_iter {
         //parse individual line
     }
}

注意,我们仍然可以在去除第一行后在正常的 for 循环中使用迭代器,它将遍历除第一行之外的所有行。此外,我们只简单地解包第一行,因为我们提供的是文件,我们可以假设它会有第一行,但这可能不适用于所有文件。

为了根据逗号分割每行,我们可以使用 split 函数,它可以接收一个字符串或字符,并输出一个包含字符串不同部分的迭代器。但我们想将这些部分存储在一个向量中,这可以通过使用 collect() 函数来完成,所以让我们将其全部封装到自己的函数中

fn split_string(input: &str) -> Vec<&str> {
    input.split(',').collect()
}

然后我们像这样更改 main 函数

fn main() {
    let csv_file = fs::read_to_string("letter_frequency.csv").unwrap();
    let mut lines_iter = csv_file.lines();
    let first_line = lines_iter.next().unwrap();
    let headers = split_string(first_line);
    // do something with headers??
    for line in lines_iter {
        //parse individual line
        let values = split_string(line);
       
        // do something with values??
    }
}

下一步:从我们的 csv 文件解析数字

华夏公益教科书