Pidgin:一个轻量级、快速且灵活的 C# 解析库

科技   2024-09-20 20:00   福建  
推荐一个专为 C# 开发者设计的轻量级、快速且灵活的解析库。

01

项目简介

Pidgin是基于C#的开源项目,是一个解析组合器库,提供了一个高级别的声明性工具来构建解析器,使得编写解析器变得简单而直观。

1、轻量化与高效

Pidgin专注于提供轻量级的解决方案,旨在减少内存占用和提高解析速度。通过精心设计的数据结构和算法,Pidgin 能够在不牺牲功能的前提下实现高效的解析。
2、灵活性
Pidgin 支持解析各种复杂的数据格式,不仅限于文本数据。由于其能够处理任意类型的输入令牌(tokens),Pidgin 可以用于解析二进制协议、标记化输入等多种场景。
3、易于使用 
与正则表达式相比,Pidgin 提供了更强大的解析能力,而与 ANTLR 等解析生成器相比,它又更简单易用。
Pidgin 的 API 设计直观,允许开发者以声明性的方式定义语法规则,而无需编写复杂的代码。

02

解析器分类

1、原始解析器
Any:表示一个使用单个字符并返回该字符的解析器。
Char:指定特定字符并返回该字符。如果遇到其他字符,则失败。
Digit:解析并返回单个数字字符。
String:解析并返回特定字符串。
Return:返回给定值。
// 使用一个解析器Char('a')来检查输入字符串"a"是否可以被解析为单个字符'a'。// 如果可以,Assert.AreEqual将验证解析结果是否为'a'。Parser<char, char> parser = Char('a');  Assert.AreEqual('a', parser.ParseOrThrow("a"));
// 使用Digit解析器来检查输入字符串"3"是否可以被解析为一个数字字符,并期望得到整数形式的'3'(尽管这里实际上得到的是字符'3')。// 注意:如果目标是得到整数类型的3,而不是字符'3',则示例可能需要调整或明确说明转换。// 但按照代码字面意思,Assert.AreEqual验证的是字符'3'。Assert.AreEqual('3', Digit.ParseOrThrow("3"));
// 创建一个解析器String("foo"),该解析器尝试从输入字符串中提取子字符串"foo"。// 如果输入字符串确实是"foo",则Assert.AreEqual将验证解析结果是否为字符串"foo"。Parser<char, string> parser = String("foo"); Assert.AreEqual("foo", parser.ParseOrThrow("foo"));
// 使用Return(3)创建一个解析器,该解析器不依赖于输入字符串,而是直接返回整数3。// 这意味着无论输入字符串是什么,解析结果都将是3。// 因此,即使输入是"foo",Assert.AreEqual仍然验证解析结果是否为整数3。Parser<char, int> parser = Return(3); Assert.AreEqual(3, parser.ParseOrThrow("foo"));
2、排序解析器
Then:顺序执行两个解析器,仅保留第二个的结果。
Before:顺序执行两个解析器,但仅保留第一个的结果。
Map:对解析器结果进行转换,不改变解析流程。
Bind:基于第一个解析器的结果选择并执行第二个解析器。
// 示例1: 使用Then(假设它保留第二个解析器的结果)  Parser<char, string> parser1 = String("foo");  Parser<char, string> parser2 = String("bar");  // 注意:这里可能需要一个特殊的Then实现,因为标准的Then可能不直接丢弃第一个结果  // 假设有一个名为ThenThatOnlyKeepsSecond的扩展方法  Parser<char, string> sequencedParser = parser1.ThenThatOnlyKeepsSecond(parser2); // 假设的方法名  Assert.AreEqual("bar", sequencedParser.ParseOrThrow("foobar"));  
// 示例2: 使用Before(假设它存在且保留第一个解析器的结果) // 注意:这通常不是标准库中的操作,但我们可以假设它存在 Parser<char, string> beforeParser = parser1.Before(parser2); // 假设的Before实现 Assert.AreEqual("foo", beforeParser.ParseOrThrow("foobar"));
// 示例3: 使用Map来合并两个解析器的结果 // 注意:这里我们假设有一个能够处理两个解析器的Map实现 Parser<char, string> mappedParser = Map((foo, bar) => bar + foo, parser1, parser2); // 假设的Map实现 Assert.AreEqual("barfoo", mappedParser.ParseOrThrow("foobar"));
// 示例4: Bind的使用(但这里给出的例子并不典型) // 假设我们想要根据输入的第一个字符来构造一个解析器,但这里我们简化它 Parser<char, char> anyCharParser = AnyChar(); // 假设的AnyChar解析器 Parser<charchar> specificCharParser = anyCharParser.Bind(c => Char(c)); // 但为了符合您的示例,我们假设它工作如下(实际上这并不实用) Assert.AreEqual('a', specificCharParser.ParseOrThrow("a")); // 这将总是返回输入的第一个字符  

3、选择替代方案
Or:表示可以解析两个备选方案之一的解析器。
OneOf:等同于Or,只不过它接受可变数量的参数。
// 定义一个能够解析字符串 "foo" 或 "bar" 的解析器  // 使用 Or 方法组合两个 String 解析器  Parser<char, string> parser = String("foo").Or(String("bar"));  
// 测试解析器是否能正确解析 "foo" Assert.AreEqual("foo", parser.ParseOrThrow("foo")); // 应该成功解析并返回 "foo"
// 测试解析器是否能正确解析 "bar" Assert.AreEqual("bar", parser.ParseOrThrow("bar")); // 应该成功解析并返回 "bar"
// 用于创建一个能够解析多个选项中任意一个的解析器 Parser<char, string> parser = OneOf(String("foo"), String("bar"));   // 测试解析器是否能正确解析 "foo" Assert.AreEqual("foo", parser.ParseOrThrow("foo")); // 应该成功解析并返回 "foo"
// 测试解析器是否能正确解析 "bar" Assert.AreEqual("bar", parser.ParseOrThrow("bar")); // 应该成功解析并返回 "bar"

4、LINQ语法

Parser<char, char> parser =    from c in Any    from c2 in Char(c)    select c2

5、递归语法

Parser<char, char> expr = null;Parser<char, char> parenthesised = Char('(')    .Then(Rec(() => expr))      .Before(Char(')'));expr = Digit.Or(parenthesised);Assert.AreEqual('1', expr.ParseOrThrow("1"));Assert.AreEqual('1', expr.ParseOrThrow("(1)"));Assert.AreEqual('1', expr.ParseOrThrow("(((1)))"));

 

03

与解析工具对比

Pidgin vs Sprache

Sprache 是另一个 C# 解析组合器库,但与 Pidgin 相比,Sprache 存在一些限制:

输入类型:Sprache 只支持字符串输入,而 Pidgin 支持任意类型的输入令牌。
性能:Pidgin 在速度和内存分配方面优于 Sprache。
文档覆盖:Pidgin 提供了更全面的文档覆盖。

Pidgin vs FParsec

FParsec 是一个为 F# 设计的解析组合器库,与 Pidgin 相比,它有以下不同:

语言支持:FParsec 是 F# 库,从 C# 调用可能不太方便。Pidgin 是为 C# 设计的。
输入类型:FParsec 仅支持字符输入流,而 Pidgin 支持任意类型的输入令牌。
性能:虽然 FParsec 在某些情况下更快,但 Pidgin 正在不断改进其性能。


04

项目地址

https://github.com/benjamin-hodgson/Pidgin

- End -

推荐阅读

2个零基础入门框架教程!

ZoneTree: 高性能ACID兼容的.NET有序键值数据库
SubtitleEdit:一个基于.Net开发的开源字幕编辑器
AutoFixture:.NET 的假数据生成工具
一个C#开源工具库,集成了超过1000个扩展方法

回复“888”,免费领取.NetCore视频教程

点击下方公众号卡片,关注我

编程乐趣
专注分享.NET和.NET Core编程知识、有趣热门的开源项目。
 最新文章