string - 使用索引比较 Rust 字符串中的字符

标签 string iterator rust

我想从“input.txt”中读取字符串,只留下行首没有#(注释)符号的字符串。我写了这段代码:

use std::io::{BufRead, BufReader};
use std::fs::File;

fn main() {
    let file = BufReader::new(File::open("input.txt").unwrap());
    let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
    let mut iter = lines.iter().filter(|&x| x.chars().next() != "#".chars().next());
    println!("{}", iter.next().unwrap());
}

但是这一行

|&x| x.chars().next() != "#".chars().next()

我闻起来很难闻,因为它看起来像这样 |x| x[0] == "#" 并且我无法检查字符串中的第二个字符。

那么我该如何重构这段代码呢?

最佳答案

Rust 字符串存储为表示 UTF-8 编码字符的字节序列。 UTF-8 是一种可变宽度编码,因此字节索引可以将您留在一个字符中,这显然是不安全的。但是通过索引获取代码点是一个 O(n) 操作。此外,索引代码点并不是您真正想要做的,因为有些代码点甚至没有关联的字符,如变音符号或其他修饰符。索引字素集群更接近于正确的方法,但在文本渲染或可能的语言处理中通常需要它。

我的意思是索引字符串很难正确定义,而且大多数人通常想要的是错误的。因此 Rust 不提供对字符串的通用索引操作。

然而,有时您确实需要索引字符串。例如,如果您事先知道您的字符串仅包含 ASCII 字符,或者您正在处理二进制数据。在这种情况下,Rust 当然提供了所有必要的方法。

首先,您始终可以获得底层字节序列的 View 。 &str 具有返回 &[u8]as_bytes() 方法,字符串由字节组成。然后你可以使用通常的索引操作:

x.as_bytes()[0] != b'#'

注意特殊符号:b'#'表示“u8类型的ASCII字符#”,即它是一个字节字符字面量(另请注意,您不需要编写 "#".chars().next() 来获取字符 #,您只需编写 '# ' - 纯字 rune 字)。但是,这是不安全的,因为 &str 是 UTF-8 编码的字符串,第一个字符可以包含多个字节。

在 Rust 中处理 ASCII 数据的正确方法是使用 ascii crate .您可以使用 as_ascii_str() 方法从 &str 转到 &AsciiStr。然后你可以像这样使用它:

extern crate ascii;
use ascii::{AsAsciiStr, AsciiChar};

// ...

x.as_ascii_str().unwrap()[0] != AsciiChar::Hash

通过这种方式,您将需要稍微多输入一些内容,但作为返回,您将获得更多的安全性,因为 as_ascii_str() 会检查您是否仅使用 ASCII 数据。

然而,有时您只想使用二进制数据,而不是真正将其解释为字符,即使源包含一些 ASCII 字符。例如,当您为某些标记语言(如 Markdown)编写解析器时,可能会发生这种情况。在这种情况下,您可以将整个输入视为一个字节序列:

use std::io::{Read, BufReader};
use std::fs::File;

fn main() {
    let mut file = BufReader::new(File::open("/etc/hosts").unwrap());
    let mut buf = Vec::new();
    file.read_to_end(&mut buf).unwrap();
    let mut iter = buf.split(|&c| c == b'\n').filter(|line| line[0] != b'#');
    println!("{:?}", iter.next().unwrap());
}

关于string - 使用索引比较 Rust 字符串中的字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26346154/

相关文章:

iterator - 有没有内置的方法来比较两个迭代器?

Popen 命令中的 Python 字符串文字

JAVA字符串反转文件io中字符串的顺序

python - 是否可以在没有单独的迭代器对象的情况下进行对象迭代?

java - 在这种情况下如何使用迭代器?

mysql - 在 mac OS 中安装 mysqlclient 库

javascript - 将 JavaScript 字符串转换为全部小写

java - StringBuilder 是否在每个操作中创建一个新的 String?

c++ - 为什么 std::list 上的 push_back 会更改用 rbegin 初始化的反向迭代器?

rust - 使用 `move` 创建闭包时的 LLVM 断言