如何将 Peekable 迭代器转换回原始迭代器?

use*_*932 6 rust

我想实现一个跳过!或!^num位于字符串开头的算法:

fn extract_common_part(a: &str) -> Option<&str> {
    let mut it = a.chars();
    if it.next() != Some('!') {
        return None;
    }
    let mut jt = it.clone().peekable();

    if jt.peek() == Some(&'^') {
        it.next();
        jt.next();
        while jt.peek().map_or(false, |v| !v.is_whitespace()) {
            it.next();
            jt.next();
        }
        it.next();
    }
    Some(it.as_str())
}

fn main() {
    assert_eq!(extract_common_part("!^4324 1234"), Some("1234"));
    assert_eq!(extract_common_part("!1234"), Some("1234"));
}
Run Code Online (Sandbox Code Playgroud)

操场

这是可行的,但我找不到从Peekableto返回的方法Chars,所以我必须前进it和jt迭代器。这会导致重复代码。

如何从Peekable迭代器返回到相应的Chars迭代器,或者也许有更简单的方法来实现该算法?

She*_*ter 6

简而言之,你不能。一般的答案是使用类似的方法Iterator::by_ref来避免消耗Chars迭代器:

fn extract_common_part(a: &str) -> Option<&str> {
    let mut it = a.chars();
    if it.next() != Some('!') {
        return None;
    }

    {
        let mut jt = it.by_ref().peekable();

        if jt.peek() == Some(&'^') {
            jt.next();
            while jt.peek().map_or(false, |v| !v.is_whitespace()) {
                jt.next();
            }
        }
    }

    Some(it.as_str())
}
Run Code Online (Sandbox Code Playgroud)

问题是,当您调用peek并且失败时,底层迭代器已经被提前。获取字符串的其余部分将丢失测试为 false 的字符,返回234。

然而,Itertools 有peeking_take_while和take_while_ref,两者都应该可以解决这个问题。

extern crate itertools;

use itertools::Itertools;

fn extract_common_part(a: &str) -> Option<&str> {
    let mut it = a.chars();
    if it.next() != Some('!') {
        return None;
    }

    if it.peeking_take_while(|&c| c == '^').next() == Some('^') {
        for _ in it.peeking_take_while(|v| !v.is_whitespace()) {}
        for _ in it.peeking_take_while(|v|  v.is_whitespace()) {}
    }

    Some(it.as_str())
}
Run Code Online (Sandbox Code Playgroud)

其他选项包括:

  • 使用像strcursor这样的包,它是为这种在字符串上增量前进而设计的。
  • 直接对常规字符串进行解析,并希望优化器消除冗余的边界检查。
  • 使用正则表达式或其他解析库

  • **免责声明**:Shepmaster 从“strcursor”的作者(即我)那里得到了“strcursor”的建议。它应该更多地作为示例,而不是作为建议。 (2认同)