人文语法库
ruler的Python项目详细描述
ruler是一个轻量级正则表达式包装器,旨在使正则表达式定义更加 模块化,直观,可读性和不匹配报告更多的信息。
快速启动
让我们实现EBNF中给出的以下语法:
grammar = who, ' likes to drink ', what; who = 'John' | 'Peter' | 'Ann' | 'Paul' | 'Rachel'; what = tea | juice; juice = 'juice'; tea = 'tea', [milk]; milk = ' with milk';
使用标尺时,它看起来几乎与EBNF:
>>> class Morning(Grammar): ... who = OneOf('John', 'Peter', 'Ann', 'Paul', 'Rachel') ... juice = Rule('juice') ... milk = Optional(' with milk') ... tea = Rule('tea', milk) ... what = OneOf(juice, tea) ... grammar = Rule(who, ' likes to drink ', what, '\.') ... ... morning = Morning.create()
名为grammar的成员必须始终存在-它充当开始规则。 让我们从不匹配开始:
>>> morning.match('John likes to drink coffee') False
match()如果匹配成功,则返回True,否则返回False。 与直接使用正则表达式相比,ruler的主要优点之一, 是否能够准确地知道出了什么问题:
>>> print(morning.error.long_description) Mismatch at 20: John likes to drink coffee ^ "coffee" does not match "juice" "coffee" does not match "tea"
让我们修正文本:
>>> morning.match('John likes to drink tea.') True
任何声明为语法类成员变量的规则都充当命名捕获组 按等级排列。使用matched属性检索与特定规则匹配的文本:
>>> morning.matched 'John likes to drink tea.' >>> morning.who.matched 'John' >>> morning.what.matched 'tea'
不匹配的某个规则和不匹配的可选规则的分支具有Noneas 他们的价值观使我们很容易询问他们是否匹配:
>>> morning.what.juice.matched is None True >>> morning.what.tea.matched is None False >>> morning.what.tea.milk.matched is None True
规则可以重复使用多次。如果同一规则在同一父项下多次出现, 这些规则被收集到一个列表中:
>>> class Morning(Grammar): ... person = OneOf('John', 'Peter', 'Ann', 'Paul', 'Rachel') ... who = Rule(person, Optional(', ', person), Optional(' and ', person)) ... juice = Rule('juice') ... milk = Optional(' with milk') ... tea = Rule('tea', milk) ... what = OneOf(juice, tea) ... grammar = Rule(who, ' like', Optional('s'), ' to drink ', what, '\.') ... ... morning = Morning.create() ... morning.match('Peter, Rachel and Ann like to drink juice.') True >>> morning.who.matched 'Peter, Rachel and Ann' >>> morning.who.person[0].matched 'Peter' >>> morning.who.person[1].matched 'Rachel' >>> morning.who.person[2].matched 'Ann'
注意,在上面的语法中,person规则从来不是who的直接子规则,但是仍然是 以这种方式访问。这是因为当一个规则层次结构被构建时,一个规则被放置在 最近命名的祖先。
rules的字符串参数实际上可以是任何有效的正则表达式。所以我们可以重写 这样的语法:
>>> class Morning(Grammar): ... who = OneOf('\w+') ... juice = Rule('juice') ... milk = Optional(' with milk') ... tea = Rule('tea', milk) ... what = OneOf(juice, tea) ... grammar = Rule(who, ' likes to drink ', what, '\.') ... ... morning = Morning() ... morning.match('R2D2 likes to drink juice. And nothing else matters.') True >>> morning.matched 'R2D2 likes to drink juice.' >>> morning.who.matched 'R2D2'
性能
为了快速匹配,库进行了很好的优化。然而,重要的是要记住 这是regex库的一个python包装器,因此永远不能超过匹配 直接使用regex库。目前尺子大约慢了十倍。 超过re。
开发
运行测试:
pytest tests
要将性能与重新库进行比较,请执行以下操作:
python performance/re_compare.py
要运行特定方法的性能分析,Rule.match例如:
python performance/profile.py Rule.match
可以在同一命令中指定多个方法。
毒性
tox不需要手动安装任何东西就可以处理所有事情。有两组毒物 环境:py*-test和py*-profile。测试环境运行单元测试,而 概要文件环境运行性能概要文件脚本。如果毒素还不够的话 创建一个新的virtualenv,然后运行 pip install -r requirements_develop.txt。
依赖性管理
为了满足开发需要,项目根目录中有三个需求文件:
- requirements_test.txt包含运行单元测试所需的所有依赖项,
- requirements_profile.txt包含运行性能分析所需的所有依赖项,
- requirements_develop.txt包含测试依赖项、分析依赖项和一些附加的 开发中使用的依赖项。
上述需求文件不用于手动编辑。相反,它们是被管理的 使用pip-tools。更新需求的过程如下:
- 在其中一个reqs_*.dep文件中添加、删除或更新依赖项:
- 更新reqs_install.dep,如果最终用户需要依赖项进行常规安装,
- 如果运行单元测试需要依赖项,但对于 常规安装,
- 如果运行性能分析需要依赖项,但不需要,则更新reqs_profile.dep。 对于常规安装,
- 如果依赖项不在前面的类别中,则更新reqs_develop.dep。
- 生成运行pip-compile的需求文件。确切的命令记录在每个 需求文件。
- 考虑运行pip-sync requirements_develop.txt。
注意,不需要编辑setup.py-它将自己从reqs_install.dep中提取依赖项。