首先大家看到这个题目,可能会不屑一顾,呵呵,是的,起初我也认为这是个很简单的任务,当任务拿到手里后,经过我作为程序员来讲已经磨炼的无比通透的大脑来讲发现这其实是个坑。

故事的起因是这样的,想开发一款给学生和老师用的产品,那么其中就少不了留作业的模块,所以咯,老师留作业,学生肯定会答作业,那么老师留作业肯定有参考答案,学生答作业肯定有学生答案,如果老师是教语文、英语、历史、政治啥的烂七八糟学科的 那么没问题,直接拿参考答案和学生答案的字符串去比较就OK了。

但是,如果是作业是数学、物理、化学的话那么就少不了使用公式了,这里前端使用的是MyScript 手写公式,非常强大可以将手写的公式转成LATEX格式的字符串。

前端将字符串获取到了,传到后台,这时候就需要我去解析做匹配了,计算学生的做题答案和教师的参考答案是否匹配。

我这里简单描述一下我的心路历程:

第一天,和同事简单沟通后,他向我推荐了一个Maple的组件,这个组件呢,说实话,通过运行cmd命令行中找到om.exe然后运行它,直接上图:

可以发现,假设a+b 为学生答案,b+a为教师的参考答案,那么直接一相减如果得0就说明计算结果是相同的,说明学生答案和参考答案是匹配的。

如果使用Maple还是要注意一点,他只识别[]中括号,所以要用之前还需对字符串进行处理,将所有的大括号全部替换成中括号。

悲哀的发现,如果使用Maple的话需要用到两个jar包,Maple.jar、externalcall.jar,启动这个引擎还需要将他用到的dll文件全部放到公共的库中,什么是公共的库,就是你配置在环境变量中的路径。可以是java/bin目录。如果这些全部都配好了,你会发现各种错误等待着你去解决....

正是因为使用这种第三方的组件,导致自己的程序过于冗余还需解决各种出现的问题,所以最终我放弃了。

第二天,我就在想能不能自己去写一个比对公式的帮助类,既轻量级又和现有项目无缝兼容。有了目标就需要有具体的想法,我在想,如何设计这个类,才能解决目前的问题呢。咱们从头再捋一遍,我的需求是:将两个字符进行公式匹配,如果最终能匹配上返回一个true,匹配不上返回false。

ok,我是这样设想的,首先我会预定义一些公式,然后用这些公式去匹配这2个字符串,记录每个公式出现的次数,如果公式出现的次数相同,则说明这2个字符串则有可能是相同的,如果公式出现的次数不同肯定不是相同的,直接返回false,那么这种匹配方式可以算为第一层的匹配。如果第一层公式次数匹配成功,则需要再进行深度匹配,何为深度匹配,就是需要将所有的公式替换成空字符串。将所有的符号,{、}、[、]、(、) 、\各种特殊的符号替换成空字符串,省下的就只有一些字母和数字以及加减乘除等运算符号了,接下来只需要将a-z的字母替换成数字 就可以进行计算了,这里我会预先将a-z设置为1-26的数字,然后循环替换掉,最终剩下的就是一组运算公式了,例如2a+2b 替换后为 21+22 这种东东,最后只需要计算一下即可,这里会用到javaScript引擎,因为它本事是弱类型脚本语言是支持这样计算的,并且好处是加减乘除的运行顺序已经帮你处理了,好了,说了这么多了,思路有了,接下来就开始实践吧,直接上干货。

公式匹配帮助类
 /**
* 将字符串转义成replace能替换的字符.
*
* @Title: convertStrByRep
* @author lmoran@163.com
* @param str
* @return
*/
public static String convertStrByRep(String str) {
str=str.replaceAll("\\\\", "\\\\\\\\")
.replaceAll("\\^", "\\\\\\^")
.replaceAll("[{]", "[{]")
.replaceAll("[}]", "[}]")
.replaceAll("\\[", "\\[")
.replaceAll("\\]", "\\]")
.replaceAll("[(]", "[(]")
.replaceAll("[(]", "[(]");
return str;
}

Util工具类中用到的方法

 package cfs.test;
import cfs.core.util.MathUtil;
public class Test { public static void main(String[] args) throws Throwable {
String str1="a+b*b+d+\\sqrt {a^{2 }}(1){2}(3)\\pi";
String str2="a+b*c+d+\\sqrt { a^ {2 }}\\pi";
boolean bool=MathUtil.twoExprPattern(str1, str2);
System.out.println(bool); } }

测试类

最后再附上一张运算后的截图:

使用java去对比2个带数学公式的字符串的更多相关文章

  1. java List<String> 转换成带逗号的字符串

    使用commons-lang3-3.3.2.jar org.apache.commons.lang3.StringUtils.join(applyNameList, ",");

  2. 【百度地图API】多家地图API内存消耗对比测验(带源码)

    原文:[百度地图API]多家地图API内存消耗对比测验(带源码) 任务描述: 啊,美妙的春节结束了.酸奶小妹和妈妈的山西平遥之旅也宣告成功!距离平遥古城7km,有一个同样身为“世界文化遗产”的寺庙,叫 ...

  3. Word带数学公式发布博客

    Word公式编辑器无法直接上传博客,一个一个的转换LaTeX还要加$,十分麻烦. 下面是我昨天摸索出来的办法.作为博客新人,这个问题困扰我一晚上,能解决我也是非常高兴的. 如果各位前辈有好方法的话,请 ...

  4. java去中文

    java 去中文 package a.b; public class TrimCNTool { public static boolean checkCNChar(char oneChar) { if ...

  5. Java 打印金字塔 or 打印带数字的金字塔 (Java 学习中的小记录)

    Java 打印金字塔 or 打印带数字的金字塔 (Java 学习中的小记录) 作者:王可利(Star·星星) 效果图: 代码如下: class Star8 { public static void m ...

  6. Java去除掉HTML里面所有标签的两种方法——开源jar包和自己写正则表达式

    Java去除掉HTML里面所有标签,主要就两种,要么用开源的jar处理,要么就自己写正则表达式.自己写的话,可能处理不全一些自定义的标签.企业应用基本都是能找开源就找开源,实在不行才自己写…… 1,开 ...

  7. DotNet,PHP,Java的数据库连接代码大全(带演示代码)

    C#数据库连接字符串 Web.config文件 <connectionStrings> <!--SQLServer数据库连接--> <add name="con ...

  8. php通过JavaBridge调用Java类库和不带包的自定义java类成功 但是调用带包的自定义Java类报错,该怎么解决

    php通过JavaBridge调用Java类库和不带包的自定义java类成功 但是调用带包的自定义Java类报错,Class.forName("com.mysql.jdbc.Driver&q ...

  9. Atitit.swift 的新特性 以及与java的对比 改进方向attilax 总结

    Atitit.swift 的新特性 以及与java的对比 改进方向attilax 总结 1. defer关键字1 2. try!形式存在的“不失败”机制3 3. Guard 4 4. swift的新语 ...

随机推荐

  1. IOS Git源代码管理工具

    .新建一个“本地仓库” $ git init .配置仓库 >告诉git你是谁 git config user.name lnj >告诉git怎么联系你 git config user.em ...

  2. 使用dao时,如何同时使用动态表名和过滤字段?

    使用dao时,如何同时使用动态表名和过滤字段?  发布于 630天前  作者 wukonggg  316 次浏览  复制  上一个帖子  下一个帖子  标签: 无 如题.求样例代码 1 回复 wend ...

  3. Android(java)学习笔记68:使用proguard混淆android代码

    1. 当前是有些工具比如apktool,dextojar等是可以对我们android安装包进行反编译,获得源码的.为了减少被别人破解,导致源码泄露,程序被别人盗取代码,等等.我们需要对代码进行混淆,a ...

  4. P1316 丢瓶盖

    题目描述 陶陶是个贪玩的孩子,他在地上丢了A个瓶盖,为了简化问题,我们可以当作这A个瓶盖丢在一条直线上,现在他想从这些瓶盖里找出B个,使得距离最近的2个距离最大,他想知道,最大可以到多少呢? 输入输出 ...

  5. Linux(三) - 文件操作相关命令

    Ctl-A 光标移动到行首 Ctl-C 终止命令 Ctl-D 注销登录 Ctl-E 光标移动到行尾 Ctl-U 删除光标到行首的所有字符,在某些设置下,删除全行 Ctl-W 删除当前光标到前边的最近一 ...

  6. css的position定位终极总结

    relative相对定位是相对于自己的位置定位,absolute绝对定位是向上级一级一级搜索有position属性的div,如果没有找到就相对于body定位

  7. node-inspector调试工具使用方法

    开发node.js程序使用的是javascript语言,其中最麻烦的还是调试,这里介绍一下node-inspector使用方法.具体资料可以看参考资料中的GITHUB文档. 工具/原料   node. ...

  8. jquery 操作css 选择器

    .addClass() 为每个匹配的元素添加指定的样式类名 .addClass(className) className 为每个匹配元素所有增加的一个或多个样式名 .addClass(function ...

  9. 求最长上升子序列(Lis模板)

    实现过程 定义已知序列数组为dp[]:dp[1…8]=389,207,155,300,299,170,158,65 我们定义一个序列B,然后令 i = 1 to 8 逐个考察这个序列.此外,我们用一个 ...

  10. 第33题:LeetCode255 Verify Preorder Sequence in Binary Search Tree 验证先序遍历是否符合二叉搜索树

    题目 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 考点 1.BST 二叉搜索树 2.递归 思路 1.后序 ...