Boost.Parser 是一个新库,目前正在审查是否包含在 Boost 中。在介绍中,该文档将 Unicode 意识作为其功能之一。
在 think-cell,多年来,我们一直在 Boost.Spirit 上标准化,以满足所有自定义解析需求,这在精神上与 Boost.Parser 相似(没有双关语)。由于 Boost.Spirit 的维护速度有点慢,我们最近分叉了我们的公共库 。我们使用它的大多数语法都很小,但有些语法更大,比如一张相互引用的 Excel 公式。
当然,我们的输入几乎完全是 Unicode,要么是 UTF-8,要么是 UTF-16。匹配 Unicode 很复杂。按代码点进行比较通常不是正确的。 相反,我们必须正常化,为此我们甚至可以选择接受什么是平等的。 不区分大小写的匹配更加复杂、缓慢,甚至依赖于语言。
通常不能保证输入是有效的 Unicode。例如,Windows 上的文件名是 16 位单位的序列,允许不匹配的代理项,与 Win32 编辑框和文件内容的输入相同。
我们意识到,对于我们拥有的几乎所有语法来说,所有这些复杂性都无关紧要。大多数语法(JSON、XML、C++、URL 等)的保留符号是纯 ASCII。语义上相关的字符串也是 ASCII(“EXCEL.EXE”)。ASCII 可以在每个代码单元的基础上正确快速地匹配。ASCII 的不区分大小写的匹配简单快捷。用户定义的字符串(例如 JSON 字符串值)可能包含 Unicode,但它们通常不会影响解析决策。用户可能希望对这些字符串进行 Unicode 验证,但这可以由叶解析器对这些字符串进行验证,而不是对整个输入完成。
由于如此多的匹配是针对 ASCII 的,我们发现在解析器库中支持编译时已知的 ASCII 文字 (tc::char_ascii) 很有用。有了它们,相同的语法可以用于任何输入编码。解析用户定义的字符串时,它们将具有输入的编码,但这很好。任何编码转换都可以与解析器分开处理。
最后,我们可能想要解析的不仅仅是字符串。解析二进制文件或 DNA 序列应该是可能且高效的。
总的来说,我建议将 Unicode 处理与解析器库分开。解析器库对符号的抽象流进行作。对于 Unicode 文本,这些将是代码单位。它提供了结构解析器,例如带和不带回溯的序列、替代项、Kleene 星形等,并将符号的解释完全留给叶解析器,叶解析器可能会也可能不关心 Unicode。
我们朝这个方向修改了库中的 Boost.Spirit 分支,它对我们很有帮助。