我正在尝试拆分一个奇怪的串行端口流,用流程返回\r
和有时\r\n
来分隔行。 BufReader
有lines
功能,但它只分裂在\n
或\r\n
。有一个.read_until(...)
函数,但它只适用于单个终止符。
基于standard library's implementation,我已经开始使用cobble together一些,但我还没有编译它。我希望我这样做是正确的“Rust方式”。对于字节流,正则表达式似乎太昂贵了。
Heading:\r\nLine 1\rLine 2\rLine 3\r\nEnd
当你在该输入上使用lines()
时,你得到三行,因为\r
不被认为是行终止符:
Heading:
Line 1\rLine 2\rLine 2\rLine 3
End
根据我之前关于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")