赞
踩
要求是这样的:
给定一段中文答案, 和标准的中文文字的答案做比对,最终得到完整的分数.
因为用户的答案中涉及到中文, 所以就必须使用中文分词器, 最终选定的是HanLP ,非常的方便, 资源链接如下:
https://github.com/hankcs/HanLP/tree/1.x 可以自行学习使用.
首先项目中引入HanLP的maven坐标:
- <dependency>
- <groupId>com.hankcs</groupId>
- <artifactId>hanlp</artifactId>
- <version>portable-1.7.7</version>
- </dependency>
我们使用HanLP分词之后, 使用 向量余弦算法计算两个文本的相似性 ,下面就是写了一个分词的工具类:
- package com.taohan.online.exam.util;
-
- import com.hankcs.hanlp.HanLP;
- import com.hankcs.hanlp.seg.common.Term;
-
- import java.math.BigDecimal;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.regex.Pattern;
-
-
- /**
- * 分词工具类
- */
- public class HanlpUtil {
-
- /**
- * 判断标点符号正则表达式, 去掉标点符号
- */
- private static Pattern PATTERN = Pattern.compile("\\pP");
-
-
- public static void main(String[] args) {
- System.out.println(cosine("天气预报说,明天会下雨,你明天早上去上班的时候记得带上伞。"
- ,"你明天早上去上班的时候记得带上伞,天气预报说的可能会下雨。"));
- }
-
-
- /**
- * 0.5543
- *
- * 词向量余弦算法计算文本相似度
- *
- * @return
- */
- public static double cosine(String userAnswer, String standAnswer) {
- List<String> originWord = getWords(standAnswer);
- List<String> targetWord = getWords(userAnswer);
- Map<String, int[]> wordDict = new HashMap<>();
- for (String word : originWord) {
- if (!wordDict.containsKey(word)) {
- int[] value = new int[2];
- value[0] = 1;
- wordDict.put(word, value);
- } else {
- wordDict.get(word)[0] += 1;
- }
- }
- for (String word : targetWord) {
- if (!wordDict.containsKey(word)) {
- int[] value = new int[2];
- value[1] = 1;
- wordDict.put(word, value);
- } else {
- wordDict.get(word)[1] += 1;
-
- }
- }
- int dictNum = 0, originNum = 0, targetNum = 0;
- for (Map.Entry<String, int[]> entry : wordDict.entrySet()) {
- int origin = entry.getValue()[0];
- int des = entry.getValue()[1];
- originNum += origin * origin;
- targetNum += des * des;
- dictNum += origin * des;
- }
- double sqrt = Math.sqrt(originNum * targetNum);
- BigDecimal scale = new BigDecimal(dictNum).divide(new BigDecimal(sqrt), 4, BigDecimal.ROUND_HALF_UP)
- .setScale(4, BigDecimal.ROUND_HALF_UP);
- return scale.doubleValue();
- }
-
-
- /**
- * 分词
- *
- * @param str
- * @return
- */
- public static List<String> getWords(String str) {
- List<String> list = new ArrayList<>();
- if (StringUtils.isBlank(str)) {
- return list;
- }
- List<Term> segment = HanLP.segment(str);
- for (Term term : segment) {
- //https://github.com/hankcs/HanLP/tree/1.x
- if (!PATTERN.matcher(term.word).matches()) {
- list.add(term.word);
- }
- }
- return list;
- }
-
- }

中文分词就解决了, 还有向量余弦算法计算文本相似度 的问题也解决了,
下面是一个用户答案的评分的工具类, 以及其使用的示例,
用户输入用户的答案, 用户答案和标准答案的多个关键字进行比较, 得到关键词双向匹配得分, 再和标准答案进行两个答案的文本比较得到相似性得分, , 两个得分计算平均值, 得到最后的得分.
- package com.taohan.online.exam.util;
-
- import java.math.BigDecimal;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
-
- public class CompareUtil {
-
-
- public static void main(String[] args) {
- String userAnswer = "多态是在程序还没运行时不知道调用哪个函数,在程序执行中,根据情况动态确定,操作很灵活";
- String standAnswer = "多态是在程序还没运行时不知道调用函数,在程序执行,根据情况动态确定";
- List<String> keywords = Stream.of("多态", "程序", "函数名", "参数", "运行情况").collect(Collectors.toList());
- double score = getUserAnswerScore(userAnswer, standAnswer, keywords);
- System.out.println(score);
-
- }
-
-
- /**
- * 获取最后的得分
- *
- * @param userAnswer 用户答案
- * @param standAnswer 标准答案
- * @param keywords 关键词
- * @return
- */
- public static double getUserAnswerScore(String userAnswer, String standAnswer, List<String> keywords) {
- if (StringUtils.equals(userAnswer, standAnswer)) {
- return 1.0;
- }
- if (StringUtils.isBlank(userAnswer)) {
- return 0.0;
- }
- double textSameScore = HanlpUtil.cosine(userAnswer, standAnswer);
- double score = 0;
- if (keywords != null && keywords.size() > 0) {
- score = getCompareScore(keywords, userAnswer);
- } else {
- score = textSameScore;
- }
- //计算两者的平均数
- BigDecimal scale = new BigDecimal(textSameScore).add(new BigDecimal(score))
- .divide(new BigDecimal(2), 4, BigDecimal.ROUND_HALF_UP)
- .setScale(4, BigDecimal.ROUND_HALF_UP);
- return scale.doubleValue();
- }
-
-
- /**
- * 0.4254
- * 获得关键词双向匹配得分
- *
- * @param keywords
- * @param userAnswer
- * @return
- */
- public static double getCompareScore(List<String> keywords, String userAnswer) {
- List<BigDecimal> list = new ArrayList<>();
- for (String keyword : keywords) {
- BigDecimal precent = getPrecent(userAnswer, keyword);
- list.add(precent);
- }
- BigDecimal sum = new BigDecimal("0");
- for (BigDecimal bigDecimal : list) {
- sum = sum.add(bigDecimal);
- }
- BigDecimal scale = sum.divide(new BigDecimal(list.size()), 4, BigDecimal.ROUND_HALF_UP)
- .setScale(4, BigDecimal.ROUND_HALF_UP);
- return scale.doubleValue();
- }
-
-
- /**
- * 比较两个字符串的相似度
- *
- * @param answer
- * @param oneWord
- * @return
- */
- public static BigDecimal getPrecent(String answer, String oneWord) {
- int index = 0;
- if (oneWord == null || oneWord.length() < 1) {
- return new BigDecimal(0);
- }
- if (answer.indexOf(oneWord) != -1) {
- index = oneWord.length();
- } else {
- int length = oneWord.length();
- for (int i = 0; i < length; i++) {
- String a = oneWord.substring(i, length - 1);
- String b = oneWord.substring(i + 1, length);
- if (answer.indexOf(a) != -1) {
- index = a.length();
- break;
- }
- if (answer.indexOf(b) != -1) {
- index = b.length();
- break;
- }
- }
- }
- if (index == 0) {
- for (int i = 0; i < oneWord.length(); i++) {
- if (answer.contains(String.valueOf(oneWord.charAt(i)))) {
- index = 1;
- }
- }
- }
- BigDecimal decimal = new BigDecimal(index)
- .divide(new BigDecimal(oneWord.length()), 2, BigDecimal.ROUND_HALF_UP)
- .setScale(4, BigDecimal.ROUND_HALF_UP);
- return decimal;
- }
-
-
- }

其实就是两个工具类的事情, 很简单.
这个是别人花钱雇我写的, 为了保证原创性, 暂时不会公开出来(大概4个月后会公开). 仅供大家参考
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。