专栏首页天马行空布鲁斯用antlr解析odata filter条件表达式

用antlr解析odata filter条件表达式

这篇文章分享如何用antlr解析odata filter条件表达式。

我最早接触antlr,是在刚开始工作后不久,那次需要用antlr实现一个功能:把gemfire的OQL(object query language)翻译成SQL语句,以便进行数据库操作。其实,简单讲,antlr就是一个非常方便的词法分析和语法分析的类库,基于这个类库,可以很容易的实现很多场景,比如计算器算术表达式的解析、各种编程语言的解析等。

印象很深刻的记得,大学编译原理的课程里面就有类似的两个练习,一个是实现计算器算术表达式的解析,一个是实现C-语言(C语言的简化版)的解析,当时肯定是需要自己手动实现,不能借助这些类库,那如何做的呢?一个很关键的点是状态机,在真正开始实现功能之前,需要根据具体问题的需求画一个状态机(个人觉得和状态图有些类似,或者说是状态图的一种形式),用状态机来描述哪些字符连一起可以构成哪种token,基于这个状态机就可以很方便的实现词法解析。其实,状态机在很多其它地方也有用途,比如:订单的状态变化,其实就可以用状态机来定义。

除了上面提到的场景,还有两个我们平时经常碰到的场景:json解析和html在线编辑器,它们都可以用antlr来实现。

具体odata filter条件表达式的定义可以参考odata官方文档,这里为了描述问题方便,简化基本规则如下:

  • 最小的表达式符合模式 key operator value
  • 表达式和表达式可以用逻辑运算符连接成一个新的表达式 expression AND expression
  • 表达式的前后可以加括号以提高优先级 (expression OR expression) AND expression

根据上面的规则,下面列举几个例子:

  1. $filter=Name eq 'John' //查询所有name等于John的人
  2. $filter=Name eq 'John' AND age ge 30 //查询所有name等于John并且年龄大于等于30岁的人
  3. $filter=(firstName eq 'John' OR firstName eq 'Bill') AND lastName eq 'Smith' //查询所有名为John或Bill,姓为Smith的人

那么,如何解析上面定义的规则呢?

首先,有一种方案:利用关键字(比如eq, AND等)来split这个filter string,在比较简单的情况下也许这个方案可行,但是如果有表达式嵌套的情况(上面第三个例子),直接split string就会有些显得力不从心。

其实,我们可以看到odata filter条件表达式和计算器的算术表达式有些类似,它们都是非常典型的词法分析和语法分析案例,所以同样可以采用antlr来解析。

如果大家以前没有接触过antlr,网上有很多关于它的资料,大家可以自行网上搜索(包括antlr官网https://www.antlr.org/)。下面仅分享一些我使用antlr(antlr 4)解析odata filter条件表达式的经验总结:

  • antlr的简单使用流程:定义grammar->生成对应语言(比如c#)的词法和语法分析代码->实现自己的Visitor遍历抽象语法树AST(abstract syntax tree)。
  • 词法定义规则须大写打头,语法定义规则须小写打头。
  • 从antlr 4.7开始,提供了对所有unicode的支持。关于这个,举一个实际的例子:由于.NET里面的正则表达式\w可以match很多国家的字符(具体有哪些,see https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-classes-in-regular-expressions#WordCharacter),如果我们需要odata filter条件表达式里面的key也支持\w可以match的字符,怎么做呢?那得益于antlr对Unicode的支持,可以像下面这样定义key: fragment VALID_ID_CHAR : [\p{General_Category=Other_Letter}\p{General_Category=Lowercase_Letter}\p{General_Category=Uppercase_Letter}\p{General_Category=Titlecase_Letter}\p{General_Category=Modifier_Letter}\p{General_Category=Nonspacing_Mark}\p{General_Category=Connector_Punctuation}\p{General_Category=Decimal_Number}] ;
  • 从antlr 4.5开始,c#的runtime换成了Antlr4.Runtime.Standard;之前的版本是用Sam Harwell提供的一个Runtime。参考https://github.com/antlr/antlr4/tree/master/runtime/CSharp。
  • Intellij的antlr的插件提供了实时preview的功能,非常方便调试;VS的插件则没有这功能。
  • 关于odata filter条件表达式的示例grammar文件,可以参考https://github.com/huazailmh/ODataFilterParser。

References

Antlr basics:

  • https://github.com/antlr/antlrcs
  • https://github.com/antlr/antlr4
  • https://github.com/tunnelvisionlabs/antlr4cs
  • https://github.com/antlr/grammars-v4

Unicode support:

  • https://github.com/antlr/antlr4/blob/master/doc/unicode.md
  • https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md#lexer-rule-elements
  • http://unicode.org/reports/tr44/#General_Category_Values
  • https://www.compart.com/en/unicode/category
  • https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-classes-in-regular-expressions#WordCharacter

本文分享自微信公众号 - 天马行空布鲁斯(gh_2feda5c053bd),作者:huazailmh

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于设计模式的那些事(一)

    通常我们说的设计模式,指的是GoF23(Gang of Four),包括23个常用的设计模式。这里尝试从不同的角度聊一聊其中几个设计模式。

    Bruce Li
  • 性能测试调优经验总结

    之前做过一些性能测试及调优相关的工作,也参加过相关的一些培训,想写一篇文章记录用过的一些工具和一些经验总结。

    Bruce Li
  • 关于html的input元素,property和attribute的区别

    之前在项目中遇到一个很tricky的关于html的input元素的问题,个人觉得挺有意思,于是记录下来。这个问题也是在ui的自动化测试中,可能会碰到的一个问题。

    Bruce Li
  • 【Rust日报】 2020-03-26 PingCAP:使用 Go 工具快速在线查找 Rust 程序瓶颈

    在线分析大型 Rust 应用程序很困难,目前常见的分析器无法胜任该工作。来自 PingCAP 官博的分享,介绍了他们在工程上是如何使用 go 工具分析 Rust...

    MikeLoveRust
  • 第4天:核心概念之广播与累加器

    广播类型变量用于跨所有节点保存数据副本。此变量缓存在所有Spark节点的机器上,而不仅仅是在执行任务的节点上保存。以下示例代码是PySpark中广播类的结构:

    会呼吸的Coder
  • 前端技术观察第12期 - 2020 年 Node.js 将会有哪些新功能

    ConardLi
  • 眼里要有光!分享一些我收藏夹里的链接

    收到了大家的催更,深表歉意。最近工作十分忙碌,连午睡时间也牺牲给了来面试的同学,放假休息了两天给身体充满了电。

    童欧巴
  • CMU发布船新「论文评审」Python程序,淘汰人工审核,自动给arXiv打分

    就在4月1日,CMU提出了最新的评审标准算法——State-Of-the-Art Review,SOAR,同时开源了它的Python程序代码。

    量子位
  • 前端技术观察第 31 期

    ConardLi
  • 2019,不可错过的NLP“高光时刻”

    谷歌AI 提出了 ALBERT 模型,这是 BERT 模型的简化版本,用于语境化语言表示的自监督学习。相较于 BERT,其在模型更加精练的同时更有效地分配了模型...

    AI科技大本营

扫码关注云+社区

领取腾讯云代金券