`

简易试卷生成系统

阅读更多
期中考试,如何机考是个难题,就用了半天时间写了这么一个试卷生成系统。基本思路很简单,就是读取题目,然后生成一个html网页,这个网页分发给学生,进行测试。考虑到机房那破电脑,就不搞b/s结构了,所有逻辑都在html中实现。
当然,有几个问题必须考虑。
一是如何自动评分
二是如何尽可能的防止zuobi
第一个问题很简单,但第二个有点头疼。这里,对答案采取base64编码。当然,如果学生懂js的,一行alert即可勘破天机。所以说,这个小系统只能用于随堂检测。


代码如下 SimpleTestGenerator.py:
import base64
class Generator:
    def __init__(self):
        self.template = '''<html>
<head>
	<title>${testName}</title>
</head>
<body>
        ${questions}
	<input type="button" onclick="submit()" value="交卷" />


<script type="text/javascript">
submitTimes=0;
duration = ${duration};
ifTimeup = false;
selNum = ${selNum}


setTimeout("timeup()",1000*60*duration);

function getRadioValue(radioName)
{
    var radios = document.getElementsByName(radioName);
    if(!radios) 
        return '';
    for (var i = 0; i < radios.length; i++) 
    {
        if (radios[i].checked) 
            return radios[i].value;
    }
   return '';
}

function submit(){
    if(ifTimeup){
        submitTimes += 1;
        a = decodeBase64("${answer}");
        score = 0;
        weight = 100/selNum;
	for(i = 0 ; i < selNum ; i++){
	     if(getRadioValue("sel"+(i+1))==a.charAt(i)){    
	         score+=weight;
	     }
	}
	alert("成绩:"+score+"分"+"  提交次数:"+submitTimes+"次");
    }else{
        alert("时间未满"+duration+"分钟"+"不能提交!")
    }
}

function timeup(){
    ifTimeup = true;
}

var END_OF_INPUT = -1;
    var base64Chars = new Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", 

"M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", 

"e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", 

"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/");
    var reverseBase64Chars = new Array();
    for (var i = 0; i < base64Chars.length; i++) {
        reverseBase64Chars[base64Chars[i]] = i
    }
    var base64Str;
    var base64Count;
    function setBase64Str(a) {
        base64Str = a;
        base64Count = 0
    }
    function readReverseBase64() {
        if (!base64Str) {
            return END_OF_INPUT
        }
        while (true) {
            if (base64Count >= base64Str.length) {
                return END_OF_INPUT
            }
            var a = base64Str.charAt(base64Count);
            base64Count++;
            if (reverseBase64Chars[a]) {
                return reverseBase64Chars[a]
            }
            if (a == "A") {
                return 0
            }
        }
        return END_OF_INPUT
    }
    function ntos(a) {
        a = a.toString(16);
        if (a.length == 1) {
            a = "0" + a
        }
        a = "%" + a;
        return unescape(a)
    }
    function decodeBase64(d) {
        setBase64Str(d);
        var a = "";
        var c = new Array(4);
        var b = false;
        while (!b && (c[0] = readReverseBase64()) != END_OF_INPUT && (c[1] = 

readReverseBase64()) != END_OF_INPUT) {
            c[2] = readReverseBase64();
            c[3] = readReverseBase64();
            a += ntos((((c[0] << 2) & 255) | c[1] >> 4));
            if (c[2] != END_OF_INPUT) {
                a += ntos((((c[1] << 4) & 255) | c[2] >> 2));
                if (c[3] != END_OF_INPUT) {
                    a += ntos((((c[2] << 6) & 255) | c[3]))
                } else {
                    b = true
                }
            } else {
                b = true
            }
        }
        return a
    }

</script>
	
</body>
</html>'''
        
    def setTestName(self,testName):
        self.testName = testName
        self.doReplace("testName",testName)

    def setDuration(self,duration):
        self.doReplace("duration",duration)

    def setQuestions(self,questions):
        self.doReplace("selNum",str(len(questions)))
        qStr = ''
        aStr = ''
        for (i,q) in enumerate(questions,start=1):
            qStr+=str(i)+") "+q.query+"<br>\n"
            for (j,o) in enumerate(q.options,start=1):
                qStr+='''<input type="radio" name="sel'''+str(i)+'''" value="'''+str(j)+'''">'''+o+'''<br>\n'''
            aStr+=str(q.answer)
        self.doReplace("questions",qStr)
        self.doReplace("answer",base64.encodestring(aStr.encode(encoding="ascii")).decode(encoding="ascii").replace('\n','\\n'))
    def doReplace(self,key,value):
        key="${"+key+"}"
        self.template = self.template.replace(key,value)
        
    def generate(self):
        f=open(self.testName+".html","w")
        f.write(self.template)
        f.close()

class Question:
    def __init__(self):
        self.query = None
        self.options = []
        self.answer = None

class Parser:
    def __init__(self,fName):
        self.fName = fName
        self.answerConvertDic = {'A':1,'B':2,'C':3,'D':4}
    def parse(self):
        fin = open(self.fName)
        self.questions = []
        q = None
        for (lno,line) in enumerate(fin.readlines()):
            line = line.strip()
            if lno==0:
                self.testName = line
            elif lno==1:
                self.duration = line
            elif (lno-2)%6==0:
                q = Question()
                q.query = line
            elif (lno-2)%6==5:
                q.answer=self.answerConvertDic[line]
                self.questions.append(q)
            else:
                q.options.append(line)



def main():
    parser = Parser("题目.txt")
    parser.parse()
    ge = Generator()
    ge.setTestName(parser.testName)
    ge.setDuration(parser.duration)
    ge.setQuestions(parser.questions)
    ge.generate()    


main()










例如若是生成题库为 题目.txt:
计算机应用基础期中检测
15
下列关于因特网上收/发电子邮件优点的描述中,错误的是________。
   A)不受时间和地域的限制,只要能接入因特网,就能收发电子邮件
   B)方便、快速
   C)费用低廉
   D)收件人必须在原电子邮箱申请地接收电子邮件
D
下列关于电子邮件的说法,正确的是________。
   A)收件人必须有E-mail地址,发件人可以没有E-mail地址
   B)发件人必须有E-mail地址,收件人可以没有E-mail地址
   C)发件人和收件人都必须有E-mail地址
   D)发件人必须知道收件人住址的邮政编码
C
假设ISP提供的邮件服务器为bj163.com,用户名为XUEJY的正确电子邮件地址是________。
   A)XUEJY @ bj163.com  
   B)XUEJYbj163.com
   C)XUEJY#bj163.com    
   D)XUEJY@bj163.com
D
用高级程序设计语言编写的程序________。
   A)计算机能直接执行             
   B)可读性和可移植性好
   C)可读性差但执行效率高         
   D)依赖于具体机器,不可移植
B

第一行为测试名称,第二行为考试时长(分钟),在这个时间之前不能交卷,也是防止学生通过反复交卷猜答案,之后的几行,是题干、选项、答案的loop;此处选择项必须是4个。


执行SimpleTestGenerator后,读取上述题库,生成的网页如下:
<html>
<head>
	<title>计算机应用基础期中检测</title>
</head>
<body>
        1) 下列关于因特网上收/发电子邮件优点的描述中,错误的是________。<br>
<input type="radio" name="sel1" value="1">A)不受时间和地域的限制,只要能接入因特网,就能收发电子邮件<br>
<input type="radio" name="sel1" value="2">B)方便、快速<br>
<input type="radio" name="sel1" value="3">C)费用低廉<br>
<input type="radio" name="sel1" value="4">D)收件人必须在原电子邮箱申请地接收电子邮件<br>
2) 下列关于电子邮件的说法,正确的是________。<br>
<input type="radio" name="sel2" value="1">A)收件人必须有E-mail地址,发件人可以没有E-mail地址<br>
<input type="radio" name="sel2" value="2">B)发件人必须有E-mail地址,收件人可以没有E-mail地址<br>
<input type="radio" name="sel2" value="3">C)发件人和收件人都必须有E-mail地址<br>
<input type="radio" name="sel2" value="4">D)发件人必须知道收件人住址的邮政编码<br>
3) 假设ISP提供的邮件服务器为bj163.com,用户名为XUEJY的正确电子邮件地址是________。<br>
<input type="radio" name="sel3" value="1">A)XUEJY @ bj163.com<br>
<input type="radio" name="sel3" value="2">B)XUEJYbj163.com<br>
<input type="radio" name="sel3" value="3">C)XUEJY#bj163.com<br>
<input type="radio" name="sel3" value="4">D)XUEJY@bj163.com<br>
4) 用高级程序设计语言编写的程序________。<br>
<input type="radio" name="sel4" value="1">A)计算机能直接执行<br>
<input type="radio" name="sel4" value="2">B)可读性和可移植性好<br>
<input type="radio" name="sel4" value="3">C)可读性差但执行效率高<br>
<input type="radio" name="sel4" value="4">D)依赖于具体机器,不可移植<br>

	<input type="button" onclick="submit()" value="交卷" />


<script type="text/javascript">
submitTimes=0;
duration = 15;
ifTimeup = false;
selNum = 4


setTimeout("timeup()",1000*60*duration);

function getRadioValue(radioName)
{
    var radios = document.getElementsByName(radioName);
    if(!radios) 
        return '';
    for (var i = 0; i < radios.length; i++) 
    {
        if (radios[i].checked) 
            return radios[i].value;
    }
   return '';
}

function submit(){
    if(ifTimeup){
        submitTimes += 1;
        a = decodeBase64("NDM0Mg==\n");
        score = 0;
        weight = 100/selNum;
	for(i = 0 ; i < selNum ; i++){
	     if(getRadioValue("sel"+(i+1))==a.charAt(i)){
	         score+=weight;
	     }
	}
	alert("成绩:"+score+"分"+"  提交次数:"+submitTimes+"次");
    }else{
        alert("时间未满"+duration+"分钟"+"不能提交!")
    }
}

function timeup(){
    ifTimeup = true;
}

var END_OF_INPUT = -1;
    var base64Chars = new Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", 

"M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", 

"e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", 

"w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/");
    var reverseBase64Chars = new Array();
    for (var i = 0; i < base64Chars.length; i++) {
        reverseBase64Chars[base64Chars[i]] = i
    }
    var base64Str;
    var base64Count;
    function setBase64Str(a) {
        base64Str = a;
        base64Count = 0
    }
    function readReverseBase64() {
        if (!base64Str) {
            return END_OF_INPUT
        }
        while (true) {
            if (base64Count >= base64Str.length) {
                return END_OF_INPUT
            }
            var a = base64Str.charAt(base64Count);
            base64Count++;
            if (reverseBase64Chars[a]) {
                return reverseBase64Chars[a]
            }
            if (a == "A") {
                return 0
            }
        }
        return END_OF_INPUT
    }
    function ntos(a) {
        a = a.toString(16);
        if (a.length == 1) {
            a = "0" + a
        }
        a = "%" + a;
        return unescape(a)
    }
    function decodeBase64(d) {
        setBase64Str(d);
        var a = "";
        var c = new Array(4);
        var b = false;
        while (!b && (c[0] = readReverseBase64()) != END_OF_INPUT && (c[1] = 

readReverseBase64()) != END_OF_INPUT) {
            c[2] = readReverseBase64();
            c[3] = readReverseBase64();
            a += ntos((((c[0] << 2) & 255) | c[1] >> 4));
            if (c[2] != END_OF_INPUT) {
                a += ntos((((c[1] << 4) & 255) | c[2] >> 2));
                if (c[3] != END_OF_INPUT) {
                    a += ntos((((c[2] << 6) & 255) | c[3]))
                } else {
                    b = true
                }
            } else {
                b = true
            }
        }
        return a
    }

</script>
	
</body>
</html>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics