【发布时间】:2017-07-15 15:50:21
【问题描述】:
我正在开发一个扫描器(如果你愿意,也可以使用标记器或词法分析器)。我必须遍历一个字符串切片。我找到了两种方法可以做到这一点:
首先,我可以创建一个迭代器并遍历每个字符。这是一个简化的例子:
let s = "чеllo".chars();
for c in s {
println!("{}", c);
}
但是,如果我想向前看,那就不那么简单了:
let mut s = "чеllo = ==".chars().peekable();
loop {
match (s.next(), s.peek()) {
(Some('='), Some(&'=')) => { s.next(); println!("==") },
(Some('='), _ ) => println!("="),
(Some(c) , _ ) => println!("{}", c),
(None, _) => break,
}
}
不幸的是,如果我想查看下一个字符,我似乎无法进行多次预览。
所以我可以改为使用 second 方法。我可以将字符串切片转换为字符向量。例如:
fn char_at(text: &Vec<char>, pos: usize) -> Option<char> {
if pos < text.len() {
Some(text[pos])
} else {
None
}
}
let mut text = "чеllo = ==".chars().collect();
let mut position: usize = 0;
loop {
match (char_at(&text, position), char_at(&text, position + 1)) {
(Some('='), Some('=')) => { position += 1; println!("==") },
(Some('='), _ ) => println!("="),
(Some(c) , _ ) => println!("{}", c),
(None , _ ) => break,
}
position += 1;
}
我现在想尝试的是第三种方法,它介于两者之间。本质上,我想要的是 Rust 之前拥有的 char_at 方法,并且我想要获得字素簇大小的能力。
如果我有这两个功能,我可以使用类似于我的字符向量方法的方法,但我可以直接在字符串切片上这样做。像这样的东西(这不是有效的 Rust 代码):
let mut text = "чеllo = ==";
let mut position: usize = 0;
loop {
let next_char = text.char_at(position);
let peek_char = text.char_at(position + next_char.len());
match (next_char, peek_char)) {
(Some('='), Some('=')) => {
position += peek_char.len();
println!("==")
},
(Some('='), _ ) => println!("="),
(Some(c) , _ ) => println!("{}", c),
(None , _ ) => break,
}
position += next_char.len();
}
注意:我想要的是 next_char.len() 和 peek_char.len() 给我这些字素组成的字节数。
这是我对上述方法的理解:
- 迭代器方法使得执行多次查看变得困难。
- 矢量方法的成本更高一些(创建矢量的时间为 O(n),并且需要更多内存)。这些成本都不算太高,但我正在努力学习更好的方法。
- 我讨论过的第三种方法介绍的方法会给我们这些非 Unicode 专家的人带来噩梦。
我是 Rust 的新手。所以这些是我的问题:
- 我是否缺少完全替代的方法?
- 是否有一种简单的方法可以向迭代器中添加多视图?
- 能否使用我目前不知道的功能来实施我的第三种方法?
【问题讨论】:
-
可以使用现有的解析库like
nom吗?你声明语法,它会为你生成一个解析器来处理这些前瞻问题。 -
@kennytm:不确定 nom 是否有字素簇的概念……但我不太确定 OP 需要从字素簇开始。
-
@drajc:老实说,我完全不知道你想在这里做什么。所以让我们先澄清一下术语:Unicode 有代码点和字素簇的概念。代码点由一个数值表示,例如
U+1F4A9(???? 表情符号),Rust 称之为char。字素簇是多个代码点的组合,它们合并在一起以表示单个(复杂)实体:组合代码点 U+0065 (e) 和 U+00B4 (´) 产生一个字素簇 (é)。在我看来,您根本不关心这些,而只是想要多窥视。 -
@drajc U+0065 和 U+0301 将显示为两个连续的
chars。您不能将两个代码点放入一个char值中,chars()一次生成一个char。 -
@drajc:如果您想一次查看多个元素,您可以使用
windows(n)迭代器,它是在底层切片上长度为n的滑动窗口。但是,您无法匹配返回的切片。否则,我建议你看看itertools;尤其是tuples迭代器。
标签: rust