2016-11-07 88 views
3

我需要迭代字符串中的行,但保留換行符中的最後一個字符串。迭代字符串中的行,包括換行符字符

str.lines(),但它返回的字符串有剁掉換行符:

let result: Vec<_> = "foo\nbar\n".lines().collect(); 
assert_eq!(result, vec!["foo", "bar"]); 

這就是我需要:

assert_eq!(lines("foo\nbar\n"), vec!["foo\n", "bar\n"]); 

多個測試用例:

assert!(lines("").is_empty()); 
assert_eq!(lines("f"), vec!["f"]); 
assert_eq!(lines("foo"), vec!["foo"]); 
assert_eq!(lines("foo\n"), vec!["foo\n"]); 
assert_eq!(lines("foo\nbar"), vec!["foo\n", "bar"]); 
assert_eq!(lines("foo\r\nbar"), vec!["foo\r\n", "bar"]); 
assert_eq!(lines("foo\r\nbar\r\n"), vec!["foo\r\n", "bar\r\n"]); 
assert_eq!(lines("\nfoo"), vec!["\n", "foo"]); 
assert_eq!(lines("\n\n\n"), vec!["\n", "\n", "\n"]); 

我有一個解決方案,基本上呼叫find在一個循環中,但我想知道是否有更優雅的東西。

這類似於Split a string keeping the separators,但在這種情況下,字符返回作爲單獨的項目,但我希望他們繼續爲字符串的一部分:

["hello\n", "world\n"]; // This 
["hello", "\n", "world", "\n"]; // Not this 

回答

2

的解決方案,我目前有看起來像這樣:

/// Iterator yielding every line in a string. The line includes newline character(s). 
pub struct LinesWithEndings<'a> { 
    input: &'a str, 
} 

impl<'a> LinesWithEndings<'a> { 
    pub fn from(input: &'a str) -> LinesWithEndings<'a> { 
     LinesWithEndings { 
      input: input, 
     } 
    } 
} 

impl<'a> Iterator for LinesWithEndings<'a> { 
    type Item = &'a str; 

    #[inline] 
    fn next(&mut self) -> Option<&'a str> { 
     if self.input.is_empty() { 
      return None; 
     } 
     let split = self.input.find('\n').map(|i| i + 1).unwrap_or(self.input.len()); 
     let (line, rest) = self.input.split_at(split); 
     self.input = rest; 
     Some(line) 
    } 
} 
+0

如果您使用'slice :: split_at',則不需要'start'參數:那麼您可以在循環的每次迭代中更新'self.input'。 –

+0

感謝@MatthieuM。,它簡化了它! – robinst