在Rust中查找字形集群的大小

时间:2017-02-24 17:40:25

标签: rust

我正在使用扫描仪(如果您愿意,还可以使用标记器或词法分析器)。我必须遍历一个字符串切片。我找到了两种方法来完成这项工作:

首先,我可以创建一个迭代器并遍历每个字符。这是一个简化的例子:

using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["myCNN"].ConnectionString))
{
    using (var cmd = new SqlCommand("dbo.myStoredProcedure", connection))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@PatientId", SqlDbType.VarChar, 40).Value = number;
        cmd.Parameters.Add("@NickName", SqlDbType.VarChar, 20).Value = "stlukeshs";                            
        var reader = cmd.ExecuteReader();
        while(reader.Read())
        {
            //Do Stuff..
        }
        //closer reader
        reader.Close();
    }
}

但是,如果我想展望未来,那就不那么简单了:

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,
    }
}

我现在要尝试的是第三种方法,它们在两者之间有点交叉。基本上,我想要的是Rust之前拥有的char_at方法,我希望能够获得字形集群的大小。

如果我有这两个功能,我可以使用类似于我的矢量字符方法的方法,但我可以直接在字符串切片上这样做。这样的事情(这不是有效的Rust代码):

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;
}

注意:我想要的是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()为我提供这些字素所包含的字节数。

以下是我对上述方法的理解:

  • 迭代器方法使得执行多方面变得困难。
  • 向量方法成本更高(创建向量时间为O(n),需要更多内存)。这些成本都不是太重要,但我正在努力学习更好的方法。
  • 我讨论过的第三种方法引入的方法会给那些不是unicode专家的人带来噩梦。

我是Rust的新手。所以这些是我的问题:

  • 我错过了一种完全替代的方法吗?
  • 是否有一种简单的方法可以向迭代器添加多方面?
  • 我的第三种方法可以使用我目前不知道的功能来实现吗?

1 个答案:

答案 0 :(得分:3)

str::chars()返回的迭代器({3}}类型实现Clone。这意味着您可以创建一个与现有迭代器具有相同状态的迭代器,但然后通过在迭代器上调用.clone()来独立迭代。您可以使用克隆进行前瞻,只有在准备好进展时才能使原始迭代器前进。

str::Chars简单地包裹iter::Slice<u8>,它本身只是一对指针。因此,克隆str::Chars只是将这两个指针复制到一个新值中,这不涉及任何内存分配。这使得克隆str::Chars非常便宜,所以不要害羞!

fn main() {
    let mut s = "чеllo = ==".chars();
    loop {
        let mut s2 = s.clone();
        let c1 = s2.next();
        let c2 = s2.next();
        match (c1, c2) {
            (Some('='), Some('=')) => { s.next(); println!("=="); }
            (Some('='), _        ) => { s.next(); println!("="); }
            (Some(c)  , _        ) => { s.next(); println!("{}", c); }
            (None, _) => break,
        }
    }
}