非字符串正则表达式,使regexp更抽象
nsre的Python项目详细描述
正则表达式用于匹配字符串,但是 这个概念可以应用到任何其他领域。这个引擎能让你匹配 使用相同类型构造的任何类型对象的任何列表 正则表达式允许。
这个算法是基于Russ Cox的this article,又名 使用汤姆森NFA算法(因为它显然更有效 但主要是因为这是我对重引擎的第一个解释 理解)。
然而,这个软件包还不支持?正则表达式语法 每个人都习惯了(因为它允许做不同的事情)。
Note — The current implementation is a pile of crap because I have no idea what I’m doing
安装
pip install nsre
然后从您的项目中,您可以
fromnsreimport*
概念演示
例如,假设您有一个字典列表,其中有一个type 指示内容类型的键。你想确认一下 列表中的模式。假设您想要一个序列,如果image,那么 有一个附加的caption,然后所有这些后面跟着一系列 text。
从概念上讲,它希望这样
(image caption?)* text+
它一旦转换为nsre,看起来就像这样
fromnsreimport*re=AnyNumber(Symbol(KeyHasValue("type","image"))+Maybe(KeyHasValue("type","caption")))+Range(KeyHasValue("type","text"),min=1)assertre.match([{"type":"image","url":"https://img1.jpg"},{"type":"image","url":"https://img2.jpg"},{"type":"image","url":"https://img3.jpg"},{"type":"caption","text":"Image 3"},{"type":"image","url":"https://img4.jpg"},{"type":"caption","text":"Image 4"},{"type":"image","url":"https://img5.jpg"},{"type":"text","text":"Hello"},{"type":"text","text":"Foo"},{"type":"text","text":"Bar"},])
示例
因为所有这些都很抽象,让我们来看看 示例:
字符串re
假设你想match a string, 传统的re是:
"([^"\\]|\\.)*"
您可以将其转换为:
re=(Symbol('"')+AnyNumber(Symbol(Neg(InSet('"\\')))|Chain(["\\",All()]))+Symbol('"'))
电子邮件验证
关于如何验证电子邮件地址有一个值得注意的争论, 但是,让我们考虑以下表达式作为练习:
[a-z]+([\.-][a-z]+)*@[a-z]+([\.\-][a-z]+)*\.[a-z]+
现在让我们看看在nsre中是如何转换的:
letter=ChrRanges(("a","z"))join=ChrRanges((".","."),("-","-"))re=(Range(letter,min=1)+AnyNumber(Symbol(join)+Range(letter,min=1))+Symbol("@")+Range(letter,min=1)+AnyNumber(Symbol(join)+Range(letter,min=1))+Symbol(".")+Range(letter,min=1))assertre.match("remy.sanchez@with-madrid.com")
参考
提供两种对象:
- 比较器-基本上相当于编写a或 [abc]在正则表达式中。它将做一个测试(等于 实例等)在所考虑的值上,以查看它是否匹配。
- fsm-构建用于测试 正则表达式。这些对象与诸如*或 ?。
比较器
InSet
检查是否在集合中找到比较的值(比查找 它在列表中,但这意味着基类型t必须是散列的)。
assertSymbol(InSet([1,2,3])).match([1])
InList
检查是否在列表中找到比较的值。意思是 基类型t必须与__eq__()相当。
assertSymbol(InList([1,2,3])).match([1])
IsInstance
测试提供的值是否是通过的任何类的实例 给构造函数。
assertSymbol(IsInstance(A,B,C)).match([A()])
AttributeHasValue
测试比较后的值,看看它们的attribute是否具有 value。
classFoo:foo='bar'assertSymbol(AttributeHasValue('foo','bar')).match([Foo()])
KeyHasValue
测试比较后的dict,看看它们的key是否具有正确的value。
assertSymbol(KeyHasValue('foo','bar')).match([{'foo':'bar'}])
Neg
否定任何比较器或原始值的输出
assertSymbol(Neg('a')).match('b')assertnotSymbol(Neg('a')).match('a')
All
匹配任何东西。
assertSymbol(All()).match('a')assertSymbol(All()).match([1])
ChrRanges
对于给定的字符,检查它是否在给定的范围内。
assertSymbol(ChrRanges(('a','z'),('A','Z'))).match('X')
fsm
符号
精确匹配1个符号
re=Symbol("a")assertre.match("a")assertnotre.match("b")assertnotre.match("aa")
链条
完全匹配一系列符号
re=Chain('hello')assertre.match('hello')
+
将两个规则相邻放置
re=Symbol('h')+Symbol('e')+Symbol('l')+Symbol('l')+Symbol('o')assertre.match('hello')
|
分支不同的选项
re=Chain('My name is ')+(Chain('Foo')|Chain('Bar'))assertre.match('My name is Foo')
可能(相当于?)
匹配0个或1个匹配项
re=Chain('Call me')+Maybe(Chain(' maybe'))assertre.match('Call me')assertre.match('Call me maybe')
任意数(相当于*)
匹配0个或多个匹配项
re=AnyNumber(Chain("na "))+Chain("Batman!")assertre.match("na na na na Batman!")
范围(相当于{min,max}和+)
来自m的匹配最大出现次数。默认情况下min为0 而max是无限的。
re=Maybe(Chain('Cam'))+Range('a',min=3)+Chain('rgh')assertre.match('Camaaaaaaaargh')
性能
太可怕了
开发
nsre本身没有依赖项,但是有几个 在requirements.txt中帮助开发的包。
安装开发依赖项
pip install -r requirements.txt
更新依赖项
编辑requirements.txt,然后运行
make venv
运行测试
单元测试使用pytest运行。
make test