前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Python神器】使用lex进行规则解释

【Python神器】使用lex进行规则解释

作者头像
明月AI
发布2021-10-28 14:49:22
1.1K0
发布2021-10-28 14:49:22
举报
文章被收录于专栏:野生AI架构师野生AI架构师

背景


在一个复杂的文章搜索匹配的需求里,匹配规则已经实现,但是原有的规则写法过于复杂,需要进行简化,例如原规则:

代码语言:javascript
复制
("小鹏" >= 1) and ("P7" >= 1)

这个规则的意思实际上是:小鹏这个关键词的出现次数大于等于1,P7这个关键词出现次数也大于等于1。

但是这个语法显然很罗嗦,客户要求进行简化。客户希望可以简化成这样:

代码语言:javascript
复制
小鹏 and P7

这是客户的习惯,实际上参考搜索引擎的查询语法是可以更加简洁的“+小鹏 +P7”,不过这暂时不再考虑范围。

上面这个只是一个简化的示例,实际客户写的匹配规则是可能很复杂的。

使用lex进行解释


同事们好像觉得这个功能实现很难,没什么信心,其实只要理解其中的逻辑,并不复杂,就算不借助工具也能实现,单单用正则和循环也能解决。不过,使用神器lex显然是更好的解决方案(lex经常和yacc搭配使用,不过我们的需求比较简单,并不需要用到yacc)。

下面是一个简单的示例:

代码语言:javascript
复制
import ply.lex as lex

# List of token names.
tokens = (
    'KEYWORD',  # 关键词
    'LPAREN',   # 左括号
    'RPAREN',   # 右括号
    'LOGIT',    # 逻辑操作
    'CMP',      # 比较操作
)

# 分组
t_LPAREN  = r'\('
t_RPAREN  = r'\)'
# 忽略空格及tab
t_ignore  = ' \t'

# 关键词
def t_KEYWORD(t):
    # 双引号内的,或者不非空格组成的字符串(不含括号)
    r'("[^\"]+")|([^\s\(\)]+)'
    val_lower = t.value.lower()
    if val_lower in {'and', 'or', 'not'}:
        t.type = 'LOGIT'
        return t
    if val_lower in {'>=', '>', '==', '<=', '<'}:
        t.type = 'CMP'
        return t
    if t.value[0] == '"':
        t.value = t.value[1:-1]    # 关键词统一去掉双引号
    return t

 # Error handling rule
def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)
# Build the lexer
lexer = lex.lex()

测试代码:

代码语言:javascript
复制
def parse_tokens(data):
    print('')
    lexer.input(data)
    while True:
        tok = lexer.token()
        if not tok: 
            break
        print(tok)

data = '小鹏 and P7'
parse_tokens(data)

# 带双引号的测试
data = '小鹏  and "P7 价格"'
parse_tokens(data)

# 带括号及比较操作的测试
data = '(小鹏 >= 2) and "P7 价格"'
parse_tokens(data)

测试对应的输出:

代码语言:javascript
复制
LexToken(KEYWORD,'小鹏',1,0)
LexToken(LOGIT,'and',1,3)
LexToken(KEYWORD,'P7',1,7)

LexToken(KEYWORD,'小鹏',1,0)
LexToken(LOGIT,'and',1,4)
LexToken(KEYWORD,'P7 价格',1,8)

LexToken(LPAREN,'(',1,0)
LexToken(KEYWORD,'小鹏',1,1)
LexToken(CMP,'>=',1,4)
LexToken(KEYWORD,'2',1,7)
LexToken(RPAREN,')',1,8)
LexToken(LOGIT,'and',1,10)
LexToken(KEYWORD,'P7 价格',1,14)

有了这个结果,要处理成完整的表达式已经是很简单了。

lex与yacc


有了这两个神器,想实现一门简单的语言也是不难的。而且,理解了这两个工具,非常有助于理解编程语言本身,可谓大有益处。

程序员还是要保持好奇心。

备注:

ply是Python Lex Yacc的缩写,官方文档:http://www.dabeaz.com/ply/ply.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 野生AI架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档