java编写正则表达式

当然,标题有点吸引人,但确实如此(您当然不相信自己没有伪造自己的基准,但这是另一回事了)。

因此,上周我正在寻找一个小型且可用的库来评估数学表达式。 我几乎直接偶然发现了这个stackoverflow帖子 。 推荐的库( Expr )确实非常快,几乎满足了我的所有需求。 但是,它没有提供限制变量范围的功能(所有内容都位于VM的一个全局命名空间中)。

因此,我做到了,通常这是我们不应该做的:我重新发明了轮子,并编写了自己的解析器/评估器。 无论如何,这是一个下雨的星期六,所以我认为一个小的递归降序解析器,一个可以简化并最终计算表达式以及一个用于管理变量的小助手的AST似乎并不重要。 事实并非如此。 我有一个初步的实现,并运行得非常快。 一旦进行了一些测试,使我相信它可以正确地计算所有内容,那么我想知道与原始文章中提到的其他库相比,评估器的速度如何。 由于没有手动优化每个内部循环和所有内容,因此我没有太大期望,毕竟有些库还是商业库。 因此,当我查看结果时,我感到非常惊讶。 下面的列表显示了一个微基准,该基准使用相应的库评估相同的表达。 我的库parsii的测量是使用最终版本完成的,该版本执行了一些简化操作,例如预先评估常量表达式。 但是,没有像字节码生成之类的“黑魔法”或类似的事情发生。

为了进行性能测量,对表达式“ 2 +(7 – 5)* 3.14159 * x ^(12-10)+ sin(-3.141)”进行了评估,其中x从0到1000000。对JIT进行10次加热。然后再次执行15次,平均执行时间为:

  • PARSII :28.3毫秒
  • 曝光 :37.2毫秒
  • MathEval :7748.5毫秒
  • JEP :647.0毫秒
  • MESP :220.8毫秒
  • JFEP :274.3毫秒

现在,我敢肯定,这些库中的每一个都有各自的优势,因此无法直接进行比较。 仍然令人惊讶的是,一个简单的实现可以很好地竞争。

对于那些不太了解编译器构造的人,下面简要介绍一下它的工作原理:

就像任何解析器或编译器一样,parsii使用经典的方法是使用分词器 ,该工具将字符流转换为令牌流。 因此,作为字符数组的“ 4”,“,”,“ +”,“”,“ 3”,“,”,“ *”,“ 8”的“ 4 + 3 * 8”将被转换为:

  • 4(整数)
  • +(符号)
  • 3(整数)
  • *(符号)
  • 8(整数)

令牌生成器查看当前字符,然后确定正在查看的令牌类型,然后读取属于该令牌的所有字符。 每个标记都有其类型,文本内容,并且知道其起始位置(行和字符)。 网上有很多深入的教程,因此在这里我不再赘述。 您可以看一下源代码,但是正如我所说的,它只是一个简单的基本实现。

解析器将经典的递归降序解析器转换为AST(抽象语法树),然后可以对其进行评估。 这是构建解析器的最简单方法之一,因为它完全是手工编写的,而不是由工具生成的。 这样的解析器基本上包含每个语法规则的方法。

再次有很多此类解析器的教程。 但是,大多数示例遗漏的是正确的错误处理。 除了正确和快速地解析表达式之外,良好的错误处理是良好的解析器的主要方面之一。 这并不难:正如您在源代码中看到的那样,解析器在解析表达式时从不抛出异常。 将收集所有错误,并且解析器将继续尽可能长的时间。 即使在出现第一个错误后,仍无法正确评估生成的AST,但仍应继续进行,并且一次运行应报告尽可能多的错误,这一点很重要。 令牌生成器使用相同的方法,因为将格式错误的令牌(例如带有两个小数分隔符的十进制数字)报告给同一错误列表。

评估AST是解析表达式的结果,这非常容易。 语法树的每个节点都有一个评估方法,该方法将由其父节点从根节点开始调用。 此处eval的结果是对表达式求值的结果。 可以在BinaryOperation中找到这种方法的基本示例,它表示+,-,*等操作。

为了稍微缩短评估时间,执行了三个优化:

首先,在解析AST之后,在根节点上调用一种称为simple的方法,该方法会传播到每个子节点。 然后,每个节点决定是否可以找到自己的子表达式的更简单表示形式。 例如:对于二进制运算 ,我们检查两个操作数是否都是常数(数字)。 在这种情况下,我们对表达式求值并返回一个包含操作结果的新常量。 对于所有参数都恒定的函数,也可以这样做。

当在表达式中使用变量时,完成第二次优化。 幼稚的方法是使用映射并在需要时读取或写入变量的值。 尽管这确实可行,但是在执行时需要进行很多查找。 因此,我们有一个名为Variable的特殊类,其中包含变量的名称和数值。 解析表达式时,将在范围(基本上只是一个映射)中查找一次该变量,然后从现在开始使用。 由于每个查找返回相同的实例,因此在评估表达式时对变量的访问与对字段的读取或写入一样便宜,因为我们仅访问Variablevalue字段。

第三次也是最后一次优化可能不会经常发挥作用。 但由于易于实现,因此还是可以实现。 它基本上被称为“惰性求值”,并在调用函数时使用。 函数不会自动求值其所有参数,然后自动执行函数调用。 它宁愿看论点,也可以凭自己决定要评估哪个论点,而不要决定。 可以在if函数中找到使用它的示例。

parsii是根据MIT许可获得许可的。 可以在GitHub上找到所有源代码以及预编译的jar。

参考: 如何在Andy的Software Engineering Corner博客上从我们的JCG合作伙伴 Andreas Haufler编写Java中最快的表达式评估器之一 。

翻译自: https://www.javacodegeeks.com/2014/01/how-to-write-one-of-the-fastest-expression-evaluators-in-java.html

java编写正则表达式

java编写正则表达式_如何用Java编写最快的表达式评估器之一相关推荐

  1. 如何用Java编写最快的表达式评估器之一

    当然,标题有点吸引人,但确实如此(您当然不相信自己没有伪造自己的基准,但这是另一回事了). 因此,上周我正在寻找一个小型且可用的库来评估数学表达式. 我几乎直接偶然发现了这个stackoverflow ...

  2. java 网络爬虫_如何用Java实现网络爬虫

    原标题:如何用Java实现网络爬虫 微信公众号"书圈"后台回复[Javapachong1],下载本例的PPT和源码 作品描述 本章作品是一个能够抓取指定网站ACM比赛信息的爬虫.A ...

  3. java 判断手机号_如何用java判断手机号运营商?

    如何用java实现判断手机号的运营商?因为每个号段都是工信部规定划分给指定运营商的,所以我们可以通过手机号码的号段来判断. 现在手机号的号段那么多,要怎样方便的的判断呢?于是我们就想到了正则表达式,在 ...

  4. 用java编写日历_如何用Java制作一个简易日历

    简易日历制作 记录一下Java实现的一个日历小程序,效果图如下: 实现以上的效果,我们需要用到两个类:SimpleDateFormat和Calendar. 首先看看这两个类的用法: 类 SimpleD ...

  5. java 一元二次方程_如何用java编写一元二次方程的求根问题

    展开全部 public class SquareEquation { double a, b, c; public void setA(double a) { this.a = a; } public ...

  6. java 设计连连看_如何用JAVA 编写一个连连看游戏全程设计

    展开全部 刚试了..测试通过.. importjavax.swing.*; importjava.awt.*; importjava.awt.event.*; publicclass LianLian ...

  7. python java 爬数据_如何用java爬虫爬取网页上的数据

    当我们使用浏览器处理网页的时候,有时候是不需要浏览的,例如使用PhantomJS适用于无头浏览器,进行爬取网页数据操作.最近在进行java爬虫学习的小伙伴们有没有想过如何爬取js生成的网络页面吗?别急 ...

  8. python编写函数_如何用Python编写自己喜欢的R函数

    python编写函数 数据科学和机器学习的伟大现代斗争之一是" Python vs. R". 毫无疑问,近年来两者都已经取得了巨大的发展,成为数据科学,预测分析和机器学习的顶级编程 ...

  9. java放大缩小_如何用Java实现图形的放大和缩小?

    展开全部 要用Java实现图形的放大和缩小,可以使636f70793231313335323631343130323136353331333365646233用以下代码: import java.aw ...

最新文章

  1. iphone 在设置了initial-scale=1 之后,在设置滚动条之后,没有滑动效果的解决办法...
  2. sj 网页前端与后台数据交互的3种方式
  3. spring scope=prototype 学习笔记
  4. 俩台电脑怎么设置同一局域网_【必看】局域网ip地址不够用怎么办?
  5. 5.hadoop常用命令
  6. 代码也浪漫:用Python放一场烟花秀!
  7. c语言程序 用追赶法求解方程组,编写用追赶法解三对角线性方程组的程序,并解下列方程组(3页)-原创力文档...
  8. hdu5791(DP)
  9. js在html中加文字走马灯特效,jQuery简单的文字跑马灯特效
  10. webserver/CGI
  11. MySQL 如何优化大分页查询?
  12. 软考系统集成项目管理工程师 | 计算题公式汇总
  13. oracle的dual用法
  14. win10总是很快自动休眠怎么解决?
  15. Im4java + ImageMagick 缩略图补白加边
  16. 做个网站要多少钱,怎么收费的?
  17. UBT7:ubuntu安装navicat15
  18. 华为到底算不算是一份好工作?看完你们还会羡慕华为的高薪吗?
  19. AXI总线信号含义说明
  20. OpenAL基本介绍

热门文章

  1. 【AC自动机】前缀匹配(ybtoj AC自动机-3)
  2. 图论复习——最小生成树MST
  3. codeforces gym-101736 Dessert First Strategy 最小割
  4. 汇编语言(十六)之三数值求和
  5. MySQL count()函数
  6. Oracle入门(十二D)之表删除与删除表数据
  7. java之正则表达式
  8. 【Python】字符串和变量拼接的写法
  9. 第四章选择结构(二)
  10. spring boot建立项目 git推送giteee