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到&AsciiStr与as_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)
| 归档时间: |
|
| 查看次数: |
4212 次 |
| 最近记录: |