我想实现一个在字符串开头跳过!
或!^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"));
}
这很有效,但我无法找到从Peekable
返回Chars
的方法,所以我必须提前it
和jt
迭代器。这会导致重复的代码。
如何从Peekable
迭代器返回到相应的Chars
迭代器,或者可能有更简单的方法来实现此算法?
答案 0 :(得分:3)
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())
}
问题在于,当您调用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())
}
其他选项包括:
答案 1 :(得分:1)
如果您只对结果感兴趣,则无需验证:
fn extract_common_part(a: &str) -> Option<&str> {
a.chars().rev().position(|v| v.is_whitespace() || v == '!')
.map(|pos| &a[a.len() - pos..])
}
fn main() {
assert_eq!(extract_common_part("!^4324 1234"), Some("1234"));
assert_eq!(extract_common_part("!1234"), Some("1234"));
}