2017-04-09 75 views
1

我想要實現在一個字符串的開頭跳過!!^num的算法:如何將Peekable迭代器轉換回原始迭代器?

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

這工作,但我不能找到辦法從PeekableChars,所以我要提前itjt迭代器。這會導致重複的代碼。

如何從Peekable迭代器返回到相應的Chars迭代器,或者可能有更簡單的方法來實現此算法?

回答

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和失敗,底層的迭代器已已經提前。獲取字符串的其餘部分將丟失測試錯誤的字符,返回234

然而,Itertools有peeking_take_whiletake_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()) 
} 

其他選項包括:

  • 使用一箱像strcursor這是專爲這種增量提前了一個字符串。
  • 直接對常規字符串進行解析,並希望優化器消除冗餘邊界檢查。
  • 使用正則表達式或其他解析庫
+0

5秒。甚至沒有得到「新答案」通知。 :P –

+1

@DK。那麼,我只會竊取我沒有說的答案部分。請注意,我不必將作者免責聲明,因此它看起來更合法;-) – Shepmaster

+2

**免責聲明**:Shepmaster從'strcursor'的作者(這是我)得到了'strcursor'的建議。它應該被視爲一個例子,而不是一個建議。 –

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