stratadox / parser
解析器组合库
v0.1.1
2023-11-13 12:26 UTC
Requires
- php: >=8.0
- ext-mbstring: *
Requires (Dev)
- phpunit/phpunit: ^9.5
- roave/security-advisories: dev-master
README
简单而强大的解析库。
这是什么
一个创建自定义解析器的库。基于“古老”的解析器组合概念,这个库包含大量基础解析器、装饰器、组合器和辅助工具。
为什么使用这个
使用此库创建的解析器可以用多种方式使用。解析是将文本转换为可使用结构的过程。
这可以用于各种目的,无论是将 json / csv / xml / yaml 等转换为某种数据结构,还是将自定义 DSL 或表达式语言解析为抽象语法树。
无论您是想创建自己的文件格式、自己的编程语言、解释现有的文件格式或语言……这个库都会为您提供帮助。
如何使用这个
有关实际操作说明,请参阅 指南。
安装
使用 composer: composer require stratadox/parser
概述
有 3 个基础解析器:any
、text
和 pattern
。
这些可以通过大量附加组件(“装饰器”)进行升级,可以根据需要组合使用。
- Repeatable 任何次数地应用解析器,生成一个列表。
- Map 基于函数修改成功的结果。
- Full Map 基于函数修改所有结果。
- Ignore 需要该对象存在,然后忽略它。(喵喵)
- Maybe 不需要它,但如果有,则使用它。
- Optional 结合上述两种。
- Except 如果另一个解析器成功,则“不匹配”。
- End 如果存在未解析的内容,则返回错误状态。
- All or Nothing 修改解析错误。
可以使用这些组合器组合解析器
- Either / Or 返回所有解析器中第一个匹配的解析器。
- Sequence / AndThen 将几个解析器一个接一个地放在一起。
上述所有内容都可以自由混合和组合。为了使生活更轻松,有一系列组合器快捷方式用于“日常任务”。
- Between 匹配解析器内容在起始和结束之间。
- Between Escaped 匹配起始和结束之间的非转义内容。
- Split 根据分隔符生成一个或多个结果。
- Must Split 根据分隔符生成两个或多个结果。
- Keep Split 生成类似
{delimiter: [left, right]}
的结构。
有几个额外的辅助工具,本质上是一些映射快捷方式
- Join 将数组结果压缩为一个字符串。
- Non-Empty 拒绝
empty
结果。 - At Least 拒绝少于 x 个条目的数组。
- At Most 拒绝多于 x 个条目的数组。
- First 将数组结果转换为它的第一个元素。
- Item 将数组结果转换为它的第 n 个元素。
要启用懒解析器(以及/或提供结构),不同类型的容器可用
- Lazy Container 管理懒加载,对于递归解析器至关重要。
- Eager Container 是基本类型化列表的常规解析器。
- Recursion-Safe Lazy Container 防止左递归时的无限循环。
- Grammar Container 混合懒加载和懒加载容器。
示例 1:CSV
对于基本“现实生活”示例,这里有一个简单的 CSV 解析器
<?php use Stratadox\Parser\Helpers\Between; use Stratadox\Parser\Parser; use function Stratadox\Parser\any; use function Stratadox\Parser\pattern; function csvParser( Parser|string $sep = ',', Parser|string $esc = '"', ): Parser { $newline = pattern('\r\n|\r|\n'); return Between::escaped('"', '"', $esc) ->or(any()->except($newline->or($sep)->or($esc))->repeatableString()) ->mustSplit($sep)->maybe() ->split($newline) ->end(); }
(有关关联结果映射,请参阅 CSV 示例)
示例 2:计算器 AST
下一个示例将基本的算术字符串(例如 1 + -3 * 3 ^ 2
)解析为抽象语法树
<?php use Stratadox\Parser\Containers\Grammar; use Stratadox\Parser\Containers\Lazy; use Stratadox\Parser\Parser; use function Stratadox\Parser\pattern; use function Stratadox\Parser\text; function calculationsParser(): Parser { $grammar = Grammar::with($lazy = Lazy::container()); $sign = text('+')->or('-')->maybe(); $digits = pattern('\d+'); $map = fn($op, $l, $r) => [ 'op' => $op, 'arg' => [$l, $r], ]; $grammar['prio 0'] = $sign->andThen($digits, '.', $digits)->join()->map(fn($x) => (float) $x) ->or($sign->andThen($digits)->join()->map(fn($x) => (int) $x)) ->between(text(' ')->or("\t", "\n", "\r")->repeatable()->optional()); $lazy['prio 1'] = $grammar['prio 0']->andThen('^', $grammar['prio 0'])->map(fn($a) => [ 'op' => '^', 'arg' => [$a[0], $a[2]], ])->or($grammar['prio 0']); $grammar['prio 2'] = $grammar['prio 1']->keepSplit(['*', '/'], $map)->or($grammar['prio 1']); $grammar['prio 3'] = $grammar['prio 2']->keepSplit(['+', '-'], $map)->or($grammar['prio 2']); return $grammar['prio 3']->end(); }
(有关工作示例,请参阅 计算器示例)