18个重大版本
0.19.0 | 2023年12月17日 |
---|---|
0.17.0 | 2023年12月9日 |
0.16.0 | 2023年10月7日 |
#607 in 解析器实现
每月213次下载
48KB
788 行
Parser Compose
已弃用。请参阅 bparse
⚠️ 警告 ☣️
下面是自制的、手工编写的代码。实验性的。可能无法按广告那样工作。
是什么?
parser-compose
是一个用于编写任意数据格式解析器的crate。您可以使用它来解析字符串切片和元素实现 Clone
的 slice
。
类似项目
这是如何不同的?
parser-compose
不提供错误处理或报告功能。如果解析成功,您将获得一个包含值的 Some(..)
。如果解析失败,您将获得一个 None
。许多解析任务不需要知道解析失败的原因,只需要知道它失败了。例如,当解析HTTP消息头时,您只需要知道它是否有效。这个crate专注于这种用例,并通过这样做摒弃了支持解析器错误处理的所有仪式。
示例
解析IMF http日期。
use parser_compose::{Parser,utf8_scalar};
struct ImfDate {
day_name: String,
day: u8,
month: String,
year: u16,
hour: u8,
minute: u8,
second: u8,
}
fn imfdate(input: &str) -> Option<(ImfDate, &str)> {
let digit = utf8_scalar(0x30..=0x39);
let twodigits = digit
.repeats(2)
.input()
.map(|s| u8::from_str_radix(s, 10).unwrap());
// day-name = %s"Mon" / %s"Tue" / %s"Wed"
// / %s"Thu" / %s"Fri" / %s"Sat" / %s"Sun"
let day_name = "Mon".or("Tue").or("Wed")
.or("Thu").or("Fri").or("Sat").or("Sun")
.map(str::to_string);
let day = twodigits;
// month = %s"Jan" / %s"Feb" / %s"Mar" / %s"Apr"
// / %s"May" / %s"Jun" / %s"Jul" / %s"Aug"
// / %s"Sep" / %s"Oct" / %s"Nov" / %s"Dec"
let month = "Jan".or("Feb").or("Mar").or("Apr")
.or("May").or("Jun").or("Jul").or("Aug")
.or("Sep").or("Oct").or("Nov").or("Dec")
.map(str::to_string);
let year = digit
.repeats(4)
.input()
.map(|s| u16::from_str_radix(s, 10).unwrap());
// date1 = day SP month SP year
let date1 = (day, " ", month, " ", year)
.map(|(d, _, m, _, y)| (d, m, y));
let gmt = "GMT";
let hour = twodigits;
let minute = twodigits;
let second = twodigits;
// time-of-day = hour ":" minute ":" second
let time_of_day = (hour, ":", minute, ":", second)
.map(|(h,_,m,_,s)| (h, m, s));
// IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
(day_name, ", ", date1, " ", time_of_day, " ", gmt)
.map(|res| ImfDate {
day_name: res.0,
day: res.2.0,
month: res.2.1,
year: res.2.2,
hour: res.4.0,
minute: res.4.1,
second: res.4.2,
}).try_parse(input)
}
let input = "Sun, 06 Nov 1994 08:49:37 GMT";
let (date, rest) = imfdate(input).unwrap();
assert_eq!(date.day_name, "Sun");
assert_eq!(date.day, 6);
assert_eq!(date.month, "Nov");
assert_eq!(date.year, 1994);
assert_eq!(date.hour, 8);
assert_eq!(date.minute, 49);
assert_eq!(date.second, 37);
// missing comma after day name
assert!(
imfdate("Sun 06 Nov 1994 08:49:37 GMT").is_none(),
);
验证http引号字符串。
use parser_compose::{Parser,byte};
/// Tries to parse a quoted string out of `input`.
/// If it succeeds, the returned tuple contains the quoted string (without
/// quotes) along with the rest of the input
fn quoted_string(input: &[u8]) -> Option<(&[u8], &[u8])> {
let htab = byte(b'\t');
let sp = byte(b' ');
let dquote = byte(b'"');
let obs_text = byte(0x80..=0xFF);
let vchar = byte(0x21..=0x7E);
// qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
let qdtext = htab
.or(sp)
.or(byte(0x21))
.or(byte(0x23..=0x5B))
.or(byte(0x5D..=0x7E))
.or(obs_text);
// quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
let quoted_pair = (
byte(b'\\'),
htab.or(sp).or(vchar).or(obs_text)
).input();
// quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
(dquote, qdtext.or(quoted_pair).repeats(0..).input(), dquote)
.map(|(_, r, _)| r)
.try_parse(input)
}
// 3 quoted strings one after the other "1", "a" and "\""
let input = r##""1""a""\"""##.as_bytes();
let (first, rest) = quoted_string(input).unwrap();
assert_eq!(
b"1",
first
);
// Notice that because of its signature, `quoted_string` can be treated as a parser
let (remaining, _) = quoted_string.accumulate(2).try_parse(rest).unwrap();
assert_eq!(remaining.len(), 2);
assert_eq!(remaining[0], b"a");
assert_eq!(remaining[1], b"\\\"");
感谢
如果没有以下内容,这个crate将无法实现:
- 这篇名为 您本可以发明解析器组合器 的帖子,它将解析器组合器的概念从“听起来像学术术语,谢谢”降低到“哇,我理解这个”
- 编写Rust解析器组合器的指南
- 这篇文章 由
pom
的作者撰写,概述了在Rust中编写解析器组合器的各种方法。