如何将流在回车符(\r)或回车换行符(CRLF, \r\n)行终止符上分割?

3
我正在尝试拆分一个奇怪的串行端口流,该流使用回车符\r分隔行,有时会使用\r\nBufReaderlines函数,但它仅在\n\r\n上拆分。有一个.read_until(...)函数,但它仅适用于单个终止符。
基于标准库的实现,我已经开始组合一些代码,但我还没有让它编译通过。我希望我正在按照“Rust方式”正确地进行操作。正则表达式对于字节流来说似乎太昂贵了。
示例输入:
Heading:\r\nLine 1\rLine 2\rLine 3\r\nEnd

当您在该输入上使用lines()时,会得到三行,因为\r不被视为行终止符:“最初的回答”
Heading:
Line 1\rLine 2\rLine 2\rLine 3
End

@trentcl 更新了问题,并附上了示例。回车符 \r 不被视为行终止符。 - undefined
相关链接:https://github.com/rust-lang/rust/issues/55743 - undefined
感谢您的更新。我还不太确定您在问什么。由于代码无法编译,代码审查似乎不太合适。如果您在编译时遇到困难,请注意应该在问题本身中提供一个 [mcve]。 - undefined
@trentcl,我正在尝试在字符串流中按照 \n、\r\n 以及最重要的 \r 进行分割。欢迎你编辑我的问题,并附上来自我的 Rust playground 链接的内容,但是这个链接很快就会过时。解决方案可能比修改我的问题更简单。 - undefined
1个回答

7

根据我之前关于GitHub的回答,以满足您的需求:

use std::io::{BufRead, BufReader};
use std::str;

#[derive(Debug)]
pub struct MyLines<B> {
    buffer: B,
}

#[derive(Debug)]
pub enum MyError {
    Io(std::io::Error),
    Utf8(std::str::Utf8Error),
}

impl<B> MyLines<B> {
    pub fn new(buffer: B) -> Self {
        Self { buffer }
    }
}

impl<B: BufRead> Iterator for MyLines<B> {
    type Item = Result<String, MyError>;

    fn next(&mut self) -> Option<Self::Item> {
        let (line, total) = {
            let buffer = match self.buffer.fill_buf() {
                Ok(buffer) => buffer,
                Err(e) => return Some(Err(MyError::Io(e))),
            };
            if buffer.is_empty() {
                return None;
            }
            let consumed = buffer
                .iter()
                .take_while(|c| **c != b'\n' && **c != b'\r')
                .count();
            let total = consumed
                + if consumed < buffer.len() {
                    // we found a delimiter
                    if consumed + 1 < buffer.len() // we look if we found two delimiter
                    && buffer[consumed] == b'\r'
                    && buffer[consumed + 1] == b'\n'
                    {
                        2
                    } else {
                        1
                    }
                } else {
                    0
                };
            let line = match str::from_utf8(&buffer[..consumed]) {
                Ok(line) => line.to_string(),
                Err(e) => return Some(Err(MyError::Utf8(e))),
            };
            (line, total)
        };
        self.buffer.consume(total);

        Some(Ok(line))
    }
}

fn main() {
    let f = BufReader::new("Heading:\r\nLine 1\rLine 2\rLine 3\r\nEnd".as_bytes());

    for line in MyLines::new(f) {
        println!("{:?}", line);
    }
}

输出:

Ok("Heading:")
Ok("Line 1")
Ok("Line 2")
Ok("Line 3")
Ok("End")

这可能导致行数比预期的要短,因为我们没有循环调用fill_buf(),正在努力改进代码。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接