我必须解析一些文件并将它们转换为一些预定义的数据类型。
Haskell 似乎为此提供了两个软件包:
它们之间的区别是什么? 哪一个更适合根据某些规则解析文本文件?
Parsec 适用于“面向用户”的解析器: 在这些解析器中,输入量有限,但错误消息很重要。它不是特别快,但是如果你有小的输入,这应该没有关系。例如,对于几乎任何编程语言工具,我都会选择 Parsec,因为——从绝对值来说——即使最大的源文件也不是 那个那么大,但错误消息确实很重要。
Parsec 可以处理不同的输入类型,这意味着您可以将它与标准的 String或来自某种外部 lexer 的令牌流一起使用。因为它可以使用 String,所以它可以很好地处理 Unicode; 内置的基本解析器(如 digit和 letter)支持 Unicode。
String
digit
letter
秒差距还附带了一个 monad transformer,这意味着你可以把它放在单子堆栈中。例如,如果您希望在解析期间跟踪其他状态,那么这可能非常有用。您还可以尝试更多的迷幻效果,比如非确定性解析,或者其他东西——单子变换器的常见魔力。
Attoparsec 比 Parsec 快得多。当您希望获得大量输入或性能真正重要时,应该使用它。它非常适合于网络代码(解析数据包结构)、解析大量原始数据或使用二进制文件格式。
Attoparsec 可以处理 ByteString,即 二进制数据。这使它成为实现二进制文件格式之类的东西的一个很好的选择。但是,因为这是针对二进制数据的,所以它不处理诸如文本编码之类的事情; 为此,您应该为 Text使用 attoparsec 模块。
ByteString
Text
Attoparsec 支持增量解析,而 Parsec 不支持。这对于某些应用程序(如网络代码)非常重要,但对于其他应用程序无关紧要。
律师 Parsec 的错误消息比 Parsec 更糟糕,并且为了性能牺牲了一些高级特性。它是专用于 Text或 ByteString的,因此您不能将它与来自自定义 lexer 的标记一起使用。也不是 monad transformer。
最终,Parsec 和 Attoparsec 迎合了非常不同的利基市场。最大的区别在于性能: 如果需要,选择 Attoparsec; 如果不需要,选择 Parsec。
我通常的启发式方法是选择 Parsec 用于编程语言、配置文件格式和用户输入,以及几乎所有我用正则表达式做的事情。这些通常是手工生成的,因此解析器不需要伸缩,但它们确实需要很好地报告错误。
另一方面,我会选择 Attoparsec 来实现网络协议、处理二进制数据和文件格式或读取大量自动生成的数据。在处理时间限制或大量数据时,通常不是由人类直接编写的。
正如您所看到的,选择实际上通常非常简单: 用例没有太多的重叠。很有可能,在任何给定的应用程序中使用哪一个都是非常清楚的。