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

Pav*_*kyi 5 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());
}
Run Code Online (Sandbox Code Playgroud)

但这一行

|&x| x.chars().next() != "#".chars().next()
Run Code Online (Sandbox Code Playgroud)

闻起来对我不好,因为它看起来像这样|x| x[0] == "#",我无法检查字符串中的第二个字符.

那我怎么能重构这段代码呢?

Vla*_*eev 10

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

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

但是,有时您需要索引字符串.例如,如果您事先知道您的字符串仅包含ASCII字符,或者您正在使用二进制数据.在这种情况下,Rust当然提供了所有必要的手段.

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

x.as_bytes()[0] != b'#'
Run Code Online (Sandbox Code Playgroud)

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

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

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

// ...

x.as_ascii_str().unwrap()[0] != AsciiChar::Hash
Run Code Online (Sandbox Code Playgroud)

这样您将需要稍微多一点的输入,但是您将获得更多的安全性,因为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());
}
Run Code Online (Sandbox Code Playgroud)

  • `x [].as_bytes()[0]!= b'#'`在任何有意义的意义上都不是*不安全*.它不会威胁到内存的安全性,它不会涉及无效的`char`值,它不会对类型做出时髦的事情,甚至不会特别容易做一些毫无意义的事情.在UTF-8中,多字节代码点专门由字节> 127(即非ASCII)组成,因此搜索值为35的字节是查找U + 0023代码点出现的完美方法.但是被授予:它是糟糕的风格,并且丢弃到字节是其他文本处理任务的坏习惯. (2认同)
  • 使用索引1来尝试检查第二个代码点或字形集群是不正确的.但是字节索引不一定是不正确的.UTF-8的属性允许子字符串搜索等字节写入.它通常是没有意义的,是的(`char`迭代器通常更好,libstd已经提供了许多算法),但是我们不要拍摄消息. (2认同)