19 个版本 (11 个重大变更)
0.12.0 | 2023年11月18日 |
---|---|
0.11.0 | 2023年7月14日 |
0.10.0 | 2023年3月8日 |
0.8.1 | 2022年12月9日 |
0.7.1 | 2021年11月27日 |
#12 in 解析器工具
每月下载量26,266
用于 6 个 crate (5 个直接使用)
115KB
2K SLoC
Yap:另一个(rust)解析库
这个小型、零依赖的 crate 通过构建在 Iterator
接口上,帮助您解析输入字符串和切片。
这个 crate 的目标是提供您从解析器组合库中期望得到的功能,但不会让您完全沉浸在解析器组合的世界中,也不会强迫您使用新颖的返回类型、库提供的错误或基于解析器组合的控制流。我们牺牲了一些简洁性,以换取简单性。
一些特定的特性/目标
- 出色的文档,几乎每个函数都提供了示例。
- 优先考虑简洁性,以牺牲冗长性为代价。
- 以迭代器为中心。在适用的情况下,组合器返回实现
Tokens
/Iterator
的东西。 - 允许在可能的地方返回用户定义的错误。一些函数有
_err
变体,以防您需要错误信息而它们又没有提供错误信息以保持简单。 - 位置信息应该始终可用,以便您可以告诉用户出错的地点。请参阅
Tokens::offset
和Tokens::location()
。 - 默认回溯。来自 Haskell 的 Parsec,这是一个合理的默认值。这意味着如果提供的解析函数之一无法解析某个内容,它将不会尝试消耗任何输入。
- 公开所有“低级”函数。您可以根据需要保存和重置位置(请参阅
Tokens::location
),并使用这些原语实现提供的任何函数。 - 旨在“相对快速”。几乎在所有地方都避免分配(并允许您通过迭代器中心接口做到这一点),如果您需要“尽可能快”,可能会有更快的替代方案。
请查看 Tokens
特性以获取所有可用的解析方法,并查看每个方法的示例。
请查看 examples
文件夹以获取更深入的示例。
示例
use yap::{
// This trait has all of the parsing methods on it:
Tokens,
// Allows you to use `.into_tokens()` on strings and slices,
// to get an instance of the above:
IntoTokens
};
// Step 1: convert our input into something implementing `Tokens`
// ================================================================
let mut tokens = "10 + 2 x 12-4,foobar".into_tokens();
// Step 2: Parse some things from our tokens
// =========================================
#[derive(PartialEq,Debug)]
enum Op { Plus, Minus, Multiply }
#[derive(PartialEq,Debug)]
enum OpOrDigit { Op(Op), Digit(u32) }
// The `Tokens` trait builds on `Iterator`, so we get a `next` method.
fn parse_op(t: &mut impl Tokens<Item=char>) -> Option<Op> {
match t.next()? {
'-' => Some(Op::Minus),
'+' => Some(Op::Plus),
'x' => Some(Op::Multiply),
_ => None
}
}
// We also get other useful functions..
fn parse_digits(t: &mut impl Tokens<Item=char>) -> Option<u32> {
t.take_while(|c| c.is_digit(10))
.parse::<u32, String>()
.ok()
}
// As well as combinator functions like `sep_by_all` and `surrounded_by`..
let op_or_digit = tokens.sep_by_all(
|t| t.surrounded_by(
|t| parse_digits(t).map(OpOrDigit::Digit),
|t| { t.skip_while(|c| c.is_ascii_whitespace()); }
),
|t| parse_op(t).map(OpOrDigit::Op)
);
// Now we've parsed our input into OpOrDigits, let's calculate the result..
let mut current_op = Op::Plus;
let mut current_digit = 0;
for d in op_or_digit.into_iter() {
match d {
OpOrDigit::Op(op) => {
current_op = op
},
OpOrDigit::Digit(n) => {
match current_op {
Op::Plus => { current_digit += n },
Op::Minus => { current_digit -= n },
Op::Multiply => { current_digit *= n },
}
},
}
}
assert_eq!(current_digit, 140);
// Step 3: do whatever you like with the rest of the input!
// ========================================================
// This is available on the concrete type that strings
// are converted into (rather than on the `Tokens` trait):
let remaining = tokens.remaining();
assert_eq!(remaining, ",foobar");