rust 迭代字符串中的各行,包括换行符

vwoqyblh  于 2023-03-18  发布在  其他
关注(0)|答案(2)|浏览(173)

我需要遍历字符串中的行,但是在生成的字符串中保留末尾的换行符。
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
ddrv8njm

ddrv8njm1#

我目前的解决方案如下所示:

/// 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)
    }
}
7kjnsjlb

7kjnsjlb2#

我的快速而肮脏的解决方案是这样的:

"foo\nbar\n".lines().map(|x| format!("{}\n", x.unwrap())).collect::<Vec<String>>()

这是可行的,因为format!宏为每一行创建了一个新的String,只是为了包含换行符。这是浪费,而且它应该比robinst的解决方案慢得多。它还使提供的Assert失败,因为您从中得到的是String s而不是&str s

相关问题