TIP
想做一个将文本处理的脚本,每次期末复习的效果感觉有点不好,在高中的时候,每天做题,感觉这样的效果会比较好一点。所以就想着能不能将期末的复习题文档转换成题库的形式。
# 需求
需求很简单,给一个带有很多题的文档,然后这个应用可以将文档转换成题库,例如:假如是一道选择题,应用可以将这道选择题分解开,选项变成可以选择的按钮,假如选的是正确的答案,这个选项会有提示正确,反之则提示错误。以后努力可以支持更多的题型。
# 分析与设计
暂时先不考虑文档的多样性。文档以txt
格式,且格式是固定的。
我觉得最难的在于如何将这一道道选择题区分开,如何将选项区分开,如何提取出选项,题号,选项号,下面就围绕上述几个问题展开分析一下。
TIP
35.在系统间提供可靠的数据传输的层次是(D)。 A、物理层 B、数据层 C、网络层 D、传输层
例如我现在拿到这样一道题,首先肯定是要取出35、D、A、B、C、D这些可以唯一确定一道题类似ID
。首先要对文档要做的就是去除空格,空格又两种,中文和英文,需要注意;其次就是需要统一括号,希望就是默认的答案就在括号里,这样可以简化寻找答案。
# 如何区分每一道题
首先要做的就是如何区分每一道题,一道题是作为一个独立的个体,必须要区分正确。每一道题的开头的都是(数字点非数字),可以以此简单的区分每一道题。代码也正是这样做的,写一个正则公式,找到所有的题号,就可以找到每道题起始的位置,则可以划分每一道题。
正则公式((\\d{1,}|[一二三])[.|、|.]{1}\\D)
,对应于上边的数字点非数字。一道题就是一个独立的单位,保存在ArrayList
中。
实现代码如下
public void Divition() {
flag = 0;
String regex = "((\\d{1,}|[一二三])[.|、|.]{1}\\D)";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(str);
int index=-1;
int end=-1;
while(matcher.find()) {
String s = matcher.group();
end=matcher.end()-2;//代表点的位置
if(s.charAt(0)=='一'||s.charAt(0)=='二'||s.charAt(0)=='三') {
flag=0;
}
else {
if(str.substring(end-flag-(s.length()-2), end).compareTo(limit[flag])>0) {
flag++;
}
}
if(index!=-1) {
whole.add(str.substring(index, end-flag-(s.length()-2)));
}
index = end-flag-(s.length()-2);//解决第一道题不是个位数只取一位问题
}
end = str.length();
whole.add(str.substring(index,end));
}
# 在一道题中提取题目
我觉得可以以遇到A
为判断条件,但是这个A
不能是题目中的单词,不能是括号中的正确答案。
在提取题目之前,我首先提取了答案,然后删掉这段答案,要不然在搜索的时候很可能与选项混淆。然后再找到第一个选项A
的位置,在此之前的都是题目,正常在题目中是不会出现单独字母的(如果出现了,现在解决不了),所以只需要保证一个字母的前后都不是字母,就可以解决了。这是对于选择题来说的,对于判断题只需要删除掉正确答案就可以了。提取完题目就删掉题目了,只剩下选项了。
正则公式:([ABCDABCDabcd]{1}[.|、|.]{1})
代码如下:
public String Subject(String s) {
String regex_T = "([ABCDABCDabcd]{1}[.|、|.]{1})";
Pattern pattern = Pattern.compile(regex_T);
Matcher matcher = pattern.matcher(s);
int index = -1;
if (matcher.find()) {
index = matcher.start();
}
position = index;
String cache = s.substring(0, index);
return cache;
}
# 在题目中提取正确答案
正确答案就在括号中,所以只需要找到括号,然后取出里面的字符就可以了。
正则公式:(\\([ABCDABCDabcd]\\))
,跟之前寻找A选项正好相反。
public String Result(String s) {
String regex_R = "(\\([ABCDABCDabcd]\\))";
Pattern pattern = Pattern.compile(regex_R);
Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
T += matcher.group().toString().charAt(1);
}
s = s.replaceAll(regex_R, "");
return s;
}
# 提取出每一个选项
题目提取完了,那就该提取选项了,碰到字母,并且这个字母是单独存在的。因为现在一道题中只剩下了选项,所以只需要找字母加上点或顿号等。
正则公式:([ABCDABCDabcd]{1}[.|、|.]{1})
判断题代码实现
public String Option(String s) {
// TODO Auto-generated method stub
String cache="";
cache += "<input type=\"radio\" id=\""+ID+"-"+"T"+"\" name=\"xxx\" />";
cache += "T";
cache += "\n<input type=\"radio\" id=\""+ID+"-"+"F"+"\" name=\"xxx\" />";
cache += "F";
cache += "\n<br />\n";
cache += "</form>\n";
return cache;
}
选择题代码实现
public String Option(String s) {
String regex_X = "([ABCDABCDabcd]{1}[.|、|.]{1})";
Pattern pattern = Pattern.compile(regex_X);
Matcher matcher = pattern.matcher(s);
int index = -1;
String cache = "";
int end = -1;
while (matcher.find()) {
end = matcher.start();
if (index != -1) {
cache += "<input type=\"radio\" id=\"" + ID + "-" + s.charAt(index) + "\" name=\"xxx\" />";
cache += s.substring(index, end);
cache += "\n<br />\n";
}
index = end;
}
end = s.length();
cache += "<input type=\"radio\" id=\"" + ID + "-" + s.charAt(index) + "\" name=\"xxx\" />";
cache += s.substring(index, end);
cache += "\n<br />\n";
cache += "</form>\n";
return cache;
}
# 实现类图
采用java语言,用正则对文本进行判断,切割。
# 重构后的实现类图
发现有点不符合开闭原则,代码重构后去除了classification
类,这样把自己的特征都写到自己的类中。特征在Rule()
方法
# 开发环境的搭建
暂时先在本地测试
# 总结
考虑到以后可能会有其他题型添加,就把一些功能分开写了,这样就可以很好的对程序扩充了;有的文档不仅有选择题还有判断题,先开始我是以题号作为ID
的,最后我把判断和选择放到一起的时候,就出现了ID
重复的问题,所以就用1-
代表判断题,2-
代表选择题,就可以解决不同题型ID
重复的问题了,相同题型,假如说题号一样的话,就会出问题了,在现在这个代码还解决不了这样的问题。