Python实现结对编程项目
开发流程
PSP2.1
|
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
|
Planning |
计划 |
60 | 90 |
|
· Estimate |
· 估计这个任务需要多少时间 |
60 | 90 |
|
Development |
开发 |
580 | 1780 |
|
· Analysis |
· 需求分析 (包括学习新技术) |
100 | 80 |
|
· Design Spec |
· 生成设计文档 |
50 | 120 |
|
· Design Review |
· 设计复审 (和同事审核设计文档) |
50 | 200 |
|
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30 | 30 |
|
· Design |
· 具体设计 |
100 | 300 |
|
· Coding |
· 具体编码 |
100 | 350 |
|
· Code Review |
· 代码复审 |
60 | 550 |
|
· Test |
· 测试(自我测试,修改代码,提交修改) |
120 | 150 |
|
Reporting |
报告 |
60 | 200 |
|
· Test Report |
· 测试报告 |
20 | 150 |
|
· Size Measurement |
· 计算工作量 |
10 | 15 |
|
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 | 35 |
|
合计 |
700 | 2070 |
- 使用 -n 参数控制生成题目的个数
- 使用 -r 参数控制题目中的数值
- 生成的题目中计算过程不能产生负数
- 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数
- 每道题目中出现的运算符个数不超过3个
- 程序一次运行生成的题目不能重复(正在努力中)
- 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
- 程序应能支持一万道题目的生成
- 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计
程序概述
(因为网页排版问题,图片字体显示比较小, 可以ctrl+鼠标滚轮放大页面显示比例或者右键该图片, 在新窗口中打开该.image, 可以看到最清晰的图片)

项目分工

该测试是生成一万条数值100内的算式, 用时437ms, 该程序耗时间大部分是生成每一条函数时调用了的随机函数


-
优化方案
-
因为randint产生最大系统耗时
-
全部换用random原始函数, 借用mod取模运算实现range功能, 避免 randint调用过程中的 randrange耗时, 使用X1,X2两个参数辅助优化符号的选择, 具体实现如下图
![]()
+ 优化Print 文件写入, 用一个字符串out先生成全部算式, 再一次性写入到文件
-
优化效果如下


设计实现过程&代码说明
Class Generate


1 class Genera: 2 3 def __init__(self, numbers, range): 4 'self.numbers 是生成题目总个数, self.range 是数值的范围' 5 self.numbers = numbers 6 self.range = range 7 self.filename = 'Exercises.txt' 8 self.Fomulas() 9 10 def GeneralOneFormula(self): 11 Range = self.range 12 # OperateNumbers = random.randint(1, 3) 13 X1 = int(random.random() * 10000) 14 X2 = int(random.random() * 10000) 15 OperateNumbers = X1 % 3 + 1 16 CountNUmbers = OperateNumbers + 1 17 Ostyle = ['+', '-', '*', '÷'] 18 19 # 生成符号list 20 Operates = [] 21 a = 0 22 while (a <= OperateNumbers): 23 # Operates.append(random.choice(Ostyle)) 24 if (a == 0): 25 Operates.append(Ostyle[X1 % 4]) 26 if (a == 1): 27 Operates.append(Ostyle[X2 % 4]) 28 if (a == 2): 29 Operates.append(Ostyle[(X1 + X2) % 4]) 30 a += 1 31 # 生成数字list与括号list 32 Counts = [] 33 i = CountNUmbers 34 while (i > 0): 35 X = int(random.random() * 10000) % Range + 1 36 if (X % 10 != 1): 37 term = str(X) 38 Counts.append(term) 39 else: 40 term = [str(X), '/', str(int(random.random() * 10000) % Range + 1)] 41 termT = ''.join(term) 42 # 此处插入分数化简 43 Counts.append(termT) 44 i -= 1 45 if ((Operates.count('-') != 0) and (Operates.count('+') != 0) and ( 46 int(random.random() * 10000) % 7 == 1)): # 假定1/7的括号生成概率 47 leftPosition = int(random.random() * 10000) % OperateNumbers 48 rightPosition = random.randint(leftPosition + 2, OperateNumbers + 1) - 1 49 # rightPosition = int(random.random() * 10000) % OperateNumbers + 1 50 term = '(' + str(Counts[leftPosition]) 51 Counts[leftPosition] = term 52 term = str(Counts[rightPosition]) + ')' 53 Counts[rightPosition] = term 54 # 合并符号list 数字括号list 55 FinalList = [] 56 j = 0 57 k = 0 58 i = OperateNumbers + CountNUmbers - 1 59 while (i >= 0): 60 if (i % 2 != 1): 61 FinalList.append(Counts[j]) 62 j += 1 63 else: 64 FinalList.append(Operates[k]) 65 k += 1 66 i -= 1 67 FinalList = ''.join(FinalList) 68 return FinalList 69 70 def Fomulas(self): 71 Range = self.range 72 Numbers = self.numbers 73 ' 生成多个Formula并写入文档 ' 74 file = open("Exercises.txt", 'a+') 75 out = "" 76 for i in range(1, Numbers + 1): 77 out = out + self.GeneralOneFormula() + '\n' 78 print(out, file=file) 79 file.close()
Class Answer

1 class Answer: 2 '这是用于生成任何题目文件的结果到Answers.txt中的类' 3 4 def __init__(self, FileName): 5 self.file = FileName 6 self.OpenAFile() 7 8 def mul_divOperation(self, s): 9 sub_str = re.search('(\d+\.?\d*[*/]-?\d+\.?\d*)', s) 10 while sub_str: 11 sub_str = sub_str.group() 12 if sub_str.count('*'): 13 l_num, r_num = sub_str.split('*') 14 s = s.replace(sub_str, str(float(l_num) * float(r_num))) 15 else: 16 l_num, r_num = sub_str.split('/') 17 s = s.replace(sub_str, str(float(l_num) / float(r_num))) 18 sub_str = re.search('(\d+\.?\d*[*/]\d+\.?\d*)', s) 19 return s 20 21 def add_minusOperation(self, s): 22 s = '+' + s 23 tmp = re.findall('[+\-]\d+\.?\d*', s) 24 s = str(functools.reduce(lambda x, y: float(x) + float(y), tmp)) 25 return s 26 27 def compute(self, formula): 28 formula = self.mul_divOperation(formula) 29 formula = self.add_minusOperation(formula) 30 return formula 31 32 def calc(self, formula): 33 """计算程序入口""" 34 if (formula[0] == '(' and formula[len(formula) - 1] == ')'): 35 formula = formula.replace('(', '') 36 formula = formula.replace(')', '') 37 formula = re.sub('[^.()/*÷\-+0-9]', "", formula) # 清除非算式符号 38 if (formula[1] == '.'): 39 formula = formula.replace(formula[0:2], '') # 计算含有题目序列号的标准算式 40 has_parenthesise = formula.count('(') 41 while has_parenthesise: 42 sub_parenthesise = re.search('\([^()]*\)', formula) # 匹配最内层括号 43 if sub_parenthesise: 44 formula = formula.replace(sub_parenthesise.group(), self.compute(sub_parenthesise.group()[1:-1])) 45 else: 46 has_parenthesise = False 47 ret = self.compute(formula) 48 return ret 49 50 def Transfer(self, formula): 51 '这是一个把小数字符串转换成分数的函数' 52 i = formula.find('.') 53 if (i != -1 and formula.find('-') == -1): # 如果存在小数点,只取小数点后三位 54 e = float(formula[0:i + 4]) 55 intE = int(e) 56 term = round(e - intE, 4) # 小数部分四舍五入 57 if (term == 0): return formula[:i] 58 termD = term * 1000 59 Deno = 1000 60 if (termD % 333 == 0): Deno = 999 # 优化小学生算术题中常出现的1/3 61 while (termD != Deno): # 求最大公约数以化简 62 if (Deno > termD): Deno = Deno - termD 63 if (termD > Deno): termD = termD - Deno 64 term = int(term * 1000 / termD) 65 Deno = int(1000 / termD) 66 if (intE != 0): answers = [str(intE), '\'', str(term), '/', str(Deno)] 67 if (intE == 0): answers = [str(term), '/', str(Deno)] 68 answers = ''.join(answers) 69 return answers 70 else: 71 return formula 72 73 def OpenAFile(self): 74 fileE = open(self.file, "r+") 75 string = fileE.read() 76 fileE.close() 77 string = string.replace('÷', '/') 78 out = "" 79 for line in string.splitlines(): 80 # out = out + self.compute(line) + '\n' 81 out = out.replace('+', '') 82 out = out + self.Transfer(self.calc(line)) + '\n' 83 fileA = open("Answers.txt", "w+") 84 print(out, file=fileA) 85 fileA.close()
Class Verify


1 class Verify: 2 '这是一个用于修正有负数结果的式子,判断式子是否有重复,以及生成题目序号的类,判断/后面有没有0' 3 4 # 筛选出等式中的符号 5 def __init__(self, FileName): 6 self.file = FileName 7 self.VerifyAFile() 8 9 def VerifyAFile(self): 10 No = 1 11 with open(self.file) as r: 12 lines = r.readlines() 13 with open('StandExercises.txt', 'w') as w: 14 for l in lines: 15 s = l 16 s = s.replace('÷', '/') 17 if ((self.math_compute(s) == 1)): 18 position = re.search('\Z', l).end() 19 l = l.replace(l[position - 1], ' = \n') 20 l = str(No) + '. ' + l 21 w.write(l) 22 No += 1 23 r.close() 24 w.close() 25 26 def filt_sym(self, e1_fs): 27 sym_get = "" 28 for sym in e1_fs: 29 if sym == '+' or sym == '-' or sym == '*' or sym == '/': 30 sym_get = sym_get + sym 31 return sym_get 32 33 # 筛选出等式中的数字 34 def filt_num(self, e1_fn): 35 num_get = [] 36 num_c = "" 37 for num in e1_fn: 38 if num != '+' and num != '-' and num != '*' and num != '/': 39 flag = 1 40 num_c += num 41 else: 42 flag = 0 43 if flag == 0: 44 num_get = num_get + [float(num_c)] 45 num_c = "" 46 num_get = num_get + [float(num_c)] 47 return num_get 48 49 # 判断优先级 50 def judge_pri(self, sym_int): 51 i = 0 52 sym_p = [] 53 for sym_jp in sym_int: 54 if sym_jp == '/': 55 sym_p += [40 + i] 56 i += 1 57 elif sym_jp == '*': 58 sym_p += [30 + i] 59 i += 1 60 else: 61 i += 1 62 i = 0 63 for sym_jp in sym_int: 64 if sym_jp == '-': 65 sym_p += [20 + i] 66 i += 1 67 elif sym_jp == '+': 68 sym_p += [10 + i] 69 i += 1 70 else: 71 i += 1 72 return sym_p 73 74 # 等式运算计算细节实现 75 def int_compute(self, num_int, sym_int): 76 sym_p_int = self.judge_pri(sym_int) 77 while sym_p_int != []: 78 sym = int(sym_p_int[0]) 79 if sym >= 40: 80 if num_int[sym - 40 + 1] == 0: 81 return -1 82 num_int[sym - 40] /= num_int[sym - 40 + 1] 83 num = num_int[sym - 40: sym - 40 + 1] 84 del num_int[sym - 40 + 1: sym - 40 + 2] 85 sym_int = sym_int[:sym - 40] + sym_int[sym - 40 + 1:] 86 elif sym >= 30: 87 num_int[sym - 30] *= num_int[sym - 30 + 1] 88 num = num_int[sym - 30: sym - 30 + 1] 89 del num_int[sym - 30 + 1: sym - 30 + 2] 90 sym_int = sym_int[:sym - 30] + sym_int[sym - 30 + 1:] 91 elif sym >= 20: 92 num_int[sym - 20] -= num_int[sym - 20 + 1] 93 num = num_int[sym - 20: sym - 20 + 1] 94 if num[0] < 0: 95 return -1 96 del num_int[sym - 20 + 1: sym - 20 + 2] 97 sym_int = sym_int[:sym - 20] + sym_int[sym - 20 + 1:] 98 elif sym >= 10: 99 num_int[sym - 10] += num_int[sym - 10 + 1] 100 num = num_int[sym - 10: sym - 10 + 1] 101 del num_int[sym - 10 + 1: sym - 10 + 2] 102 sym_int = sym_int[:sym - 10] + sym_int[sym - 10 + 1:] 103 sym_p_int = self.judge_pri(sym_int) 104 return float(num[0]) 105 106 # 等式运算 107 def compute_c(self, e1): 108 num_int = float() 109 num_int = self.filt_num(e1) 110 sym_int = self.filt_sym(e1) 111 flag = self.int_compute(num_int, sym_int) 112 if flag < 0: 113 return 'f' 114 else: 115 return str(flag) 116 117 # 将等式中括号里面的等式提取出来 118 def judge_bracket(self, equ_j): 119 left = equ_j.rfind('(') 120 right = equ_j.find(')', left) 121 e1 = equ_j[left + 1:right] 122 c1 = self.compute_c(e1) 123 if c1 == 'f': 124 return False 125 equ_j = equ_j[0:left] + str(c1) + equ_j[(left + len(c1)):] 126 equ_j = equ_j[0: left + len(str(c1))] + equ_j[right + 1:] 127 return equ_j 128 129 def math_compute(self, equation): 130 equ_m = equation 131 while equ_m.find('(') != -1: 132 if equ_m.find('(') != -1: 133 equ_m = self.judge_bracket(equ_m) 134 if not equ_m: 135 break; 136 else: 137 break 138 if not equ_m: 139 return 0 140 elif equ_m.find('+') != -1 or equ_m.find('-') != -1 or equ_m.find('*') != -1 or equ_m.find('/') != -1: 141 val = self.compute_c(equ_m) 142 if val == 'f': 143 return 0 144 else: 145 return 1 146 else: 147 return 1
Class Judge

Class Judge

1 class Judge: 2 '判断Exercises 和 Answers.txt ,并返回处理结果' 3 4 def __init__(self, FileName, FilenameAns): 5 self.user_file = FileName 6 self.standAns_file = FilenameAns 7 self.judge_ans(self.user_file, self.standAns_file) 8 9 def judge_ans(self, user_ans, stand_ans): 10 user_a = open(user_ans, 'r') 11 std_a = open(stand_ans, 'r') 12 i = 0 13 c_sum = [] 14 e_sum = [] 15 while 1: 16 equa_u = user_a.readline() 17 equa_s = std_a.readline() 18 if not equa_u: 19 break 20 ind = equa_u.rfind('=') 21 if equa_u[ind + 1:].strip() == equa_s.strip(): 22 i += 1 23 c_sum += [i] 24 else: 25 i += 1 26 e_sum += [i] 27 print("Correct: ", len(c_sum), c_sum) 28 print("Wrong: ", len(e_sum), e_sum)
命令行传参代码

1 from optparse import OptionParser 2 3 usage = "[<-n> + 数字] 确定题目条数 [<-r> + 数字] 确定数字范围 \n 可选参数: \n <-u> 生成有负数出现的题目 \n [<-a> + (filename)] 回答filename文件的题目 \n [<-j> + (filename)] 批改filename文件的题目" 4 parser = OptionParser(usage) 5 parser.print_help() 6 parser.add_option("-n", action='store', type='int', dest='Numbers', help="生成Numbers条无负数结果的算式,输出文件是StandExercises.txt") 7 parser.add_option("-r", action='store', type='int', dest='Range', help="指定数字Range范围") 8 parser.add_option("-u", action='store', type='string', dest='ProExFile', help="生成Numbers条有负数结果的算式,输出文件时Exercises.txt") 9 parser.add_option("-a", action='store', type='string', dest='AnsFile', help="指定题目文件,并生成答案到Answers.txt") 10 parser.add_option("-j", action='store', type='string', dest='JudgeFile', help="指定用户答案文件,并将其和标准Answers.txt对比") 11 options, args = parser.parse_args() 12 13 if options.Numbers and options.Range and options.ProExFile: 14 '生成Numbers条有负数结果的算式, 再将其标准化(去除中间过程有负数结果的算式以及/后面有0的非法算式), 输出文件是StandExercises.txt' 15 fileE = Genera(options.Numbers, options.Range) 16 fileStand = Verify(fileE.filename) 17 18 if options.Numbers and options.Range and options.ProExFile and options.AnsFile: 19 '生成Numbers条有负数结果的算式, 再将其标准化(去除中间过程有负数结果的算式以及/后面有0的非法算式), 输出文件是StandExercises.txt' 20 fileE = Genera(options.Numbers, options.Range) 21 fileStand = Verify(fileE.filename) 22 fileA = Answer(options.AnsFile) 23 24 if options.AnsFile and not options.Numbers: 25 '回答-a后面的filename题目文件,并输出结果到Answers.txt文件' 26 fileA = Answer(options.AnsFile) 27 28 if options.ProExFile and options.Numbers and options.Range and not options.AnsFile: 29 '生成Numbers条有负数结果的算式, 生成文件是Exercises.txt' 30 fileE = Genera(options.Numbers, options.Range) 31 32 if options.JudgeFile and not options.Numbers and not options.Range and not options.ProExFile: 33 '-j 接一个用户的答案文件, 并将其和标准答案文件Answers.txt比较' 34 FileA = Judge(options.JudgeFile, "Answers.txt")
全部代码1 import re 2 import functools 3 # -*- coding: UTF-8 -*- 4 import random 5 from optparse import OptionParser 6 7 usage = "[<-n> + 数字] 确定题目条数 [<-r> + 数字] 确定数字范围 \n 可选参数: \n <-u> 生成有负数出现的题目 \n [<-a> + (filename)] 回答filename文件的题目 \n [<-j> + (filename)] 批改filename文件的题目" 8 parser = OptionParser(usage) 9 parser.print_help() 10 parser.add_option("-n", action='store', type='int', dest='Numbers', help="生成Numbers条无负数结果的算式,输出文件是StandExercises.txt") 11 parser.add_option("-r", action='store', type='int', dest='Range', help="指定数字Range范围") 12 parser.add_option("-u", action='store', type='string', dest='ProExFile', help="生成Numbers条有负数结果的算式,输出文件时Exercises.txt") 13 parser.add_option("-a", action='store', type='string', dest='AnsFile', help="指定题目文件,并生成答案到Answers.txt") 14 parser.add_option("-j", action='store', type='string', dest='JudgeFile', help="指定用户答案文件,并将其和标准Answers.txt对比") 15 options, args = parser.parse_args() 16 17 18 class Genera: 19 20 def __init__(self, numbers, range): 21 'self.numbers 是生成题目总个数, self.range 是数值的范围' 22 self.numbers = numbers 23 self.range = range 24 self.filename = 'Exercises.txt' 25 self.Fomulas() 26 27 def GeneralOneFormula(self): 28 Range = self.range 29 # OperateNumbers = random.randint(1, 3) 30 X1 = int(random.random() * 10000) 31 X2 = int(random.random() * 10000) 32 OperateNumbers = X1 % 3 + 1 33 CountNUmbers = OperateNumbers + 1 34 Ostyle = ['+', '-', '*', '÷'] 35 36 # 生成符号list 37 Operates = [] 38 a = 0 39 while (a <= OperateNumbers): 40 # Operates.append(random.choice(Ostyle)) 41 if (a == 0): 42 Operates.append(Ostyle[X1 % 4]) 43 if (a == 1): 44 Operates.append(Ostyle[X2 % 4]) 45 if (a == 2): 46 Operates.append(Ostyle[(X1 + X2) % 4]) 47 a += 1 48 # 生成数字list与括号list 49 Counts = [] 50 i = CountNUmbers 51 while (i > 0): 52 X = int(random.random() * 10000) % Range + 1 53 if (X % 10 != 1): 54 term = str(X) 55 Counts.append(term) 56 else: 57 term = [str(X), '/', str(int(random.random() * 10000) % Range + 1)] 58 termT = ''.join(term) 59 # 此处插入分数化简 60 Counts.append(termT) 61 i -= 1 62 if ((Operates.count('-') != 0) and (Operates.count('+') != 0) and ( 63 int(random.random() * 10000) % 7 == 1)): # 假定1/7的括号生成概率 64 leftPosition = int(random.random() * 10000) % OperateNumbers 65 rightPosition = random.randint(leftPosition + 2, OperateNumbers + 1) - 1 66 # rightPosition = int(random.random() * 10000) % OperateNumbers + 1 67 term = '(' + str(Counts[leftPosition]) 68 Counts[leftPosition] = term 69 term = str(Counts[rightPosition]) + ')' 70 Counts[rightPosition] = term 71 # 合并符号list 数字括号list 72 FinalList = [] 73 j = 0 74 k = 0 75 i = OperateNumbers + CountNUmbers - 1 76 while (i >= 0): 77 if (i % 2 != 1): 78 FinalList.append(Counts[j]) 79 j += 1 80 else: 81 FinalList.append(Operates[k]) 82 k += 1 83 i -= 1 84 FinalList = ''.join(FinalList) 85 return FinalList 86 87 def Fomulas(self): 88 Range = self.range 89 Numbers = self.numbers 90 ' 生成多个Formula并写入文档 ' 91 file = open("Exercises.txt", 'a+') 92 out = "" 93 for i in range(1, Numbers + 1): 94 out = out + self.GeneralOneFormula() + '\n' 95 print(out, file=file) 96 file.close() 97 98 99 class Answer: 100 '这是用于生成任何题目文件的结果到Answers.txt中的类' 101 102 def __init__(self, FileName): 103 self.file = FileName 104 self.OpenAFile() 105 106 def mul_divOperation(self, s): 107 sub_str = re.search('(\d+\.?\d*[*/]-?\d+\.?\d*)', s) 108 while sub_str: 109 sub_str = sub_str.group() 110 if sub_str.count('*'): 111 l_num, r_num = sub_str.split('*') 112 s = s.replace(sub_str, str(float(l_num) * float(r_num))) 113 else: 114 l_num, r_num = sub_str.split('/') 115 s = s.replace(sub_str, str(float(l_num) / float(r_num))) 116 sub_str = re.search('(\d+\.?\d*[*/]\d+\.?\d*)', s) 117 return s 118 119 def add_minusOperation(self, s): 120 s = '+' + s 121 tmp = re.findall('[+\-]\d+\.?\d*', s) 122 s = str(functools.reduce(lambda x, y: float(x) + float(y), tmp)) 123 return s 124 125 def compute(self, formula): 126 formula = self.mul_divOperation(formula) 127 formula = self.add_minusOperation(formula) 128 return formula 129 130 def calc(self, formula): 131 """计算程序入口""" 132 if (formula[0] == '(' and formula[len(formula) - 1] == ')'): 133 formula = formula.replace('(', '') 134 formula = formula.replace(')', '') 135 formula = re.sub('[^.()/*÷\-+0-9]', "", formula) # 清除非算式符号 136 if (formula[1] == '.'): 137 formula = formula.replace(formula[0:2], '') # 计算含有题目序列号的标准算式 138 has_parenthesise = formula.count('(') 139 while has_parenthesise: 140 sub_parenthesise = re.search('\([^()]*\)', formula) # 匹配最内层括号 141 if sub_parenthesise: 142 formula = formula.replace(sub_parenthesise.group(), self.compute(sub_parenthesise.group()[1:-1])) 143 else: 144 has_parenthesise = False 145 ret = self.compute(formula) 146 return ret 147 148 def Transfer(self, formula): 149 '这是一个把小数字符串转换成分数的函数' 150 i = formula.find('.') 151 if (i != -1 and formula.find('-') == -1): # 如果存在小数点,只取小数点后三位 152 e = float(formula[0:i + 4]) 153 intE = int(e) 154 term = round(e - intE, 4) # 小数部分四舍五入 155 if (term == 0): return formula[:i] 156 termD = term * 1000 157 Deno = 1000 158 if (termD % 333 == 0): Deno = 999 # 优化小学生算术题中常出现的1/3 159 while (termD != Deno): # 求最大公约数以化简 160 if (Deno > termD): Deno = Deno - termD 161 if (termD > Deno): termD = termD - Deno 162 term = int(term * 1000 / termD) 163 Deno = int(1000 / termD) 164 if (intE != 0): answers = [str(intE), '\'', str(term), '/', str(Deno)] 165 if (intE == 0): answers = [str(term), '/', str(Deno)] 166 answers = ''.join(answers) 167 return answers 168 else: 169 return formula 170 171 def OpenAFile(self): 172 fileE = open(self.file, "r+") 173 string = fileE.read() 174 fileE.close() 175 string = string.replace('÷', '/') 176 out = "" 177 for line in string.splitlines(): 178 # out = out + self.compute(line) + '\n' 179 out = out.replace('+', '') 180 out = out + self.Transfer(self.calc(line)) + '\n' 181 fileA = open("Answers.txt", "w+") 182 print(out, file=fileA) 183 fileA.close() 184 185 186 class Verify: 187 '这是一个用于修正有负数结果的式子,判断式子是否有重复,以及生成题目序号的类,判断/后面有没有0' 188 189 # 筛选出等式中的符号 190 def __init__(self, FileName): 191 self.file = FileName 192 self.VerifyAFile() 193 194 def VerifyAFile(self): 195 No = 1 196 with open(self.file) as r: 197 lines = r.readlines() 198 with open('StandExercises.txt', 'w') as w: 199 for l in lines: 200 s = l 201 s = s.replace('÷', '/') 202 if ((self.math_compute(s) == 1)): 203 position = re.search('\Z', l).end() 204 l = l.replace(l[position - 1], ' = \n') 205 l = str(No) + '. ' + l 206 w.write(l) 207 No += 1 208 r.close() 209 w.close() 210 211 def filt_sym(self, e1_fs): 212 sym_get = "" 213 for sym in e1_fs: 214 if sym == '+' or sym == '-' or sym == '*' or sym == '/': 215 sym_get = sym_get + sym 216 return sym_get 217 218 # 筛选出等式中的数字 219 def filt_num(self, e1_fn): 220 num_get = [] 221 num_c = "" 222 for num in e1_fn: 223 if num != '+' and num != '-' and num != '*' and num != '/': 224 flag = 1 225 num_c += num 226 else: 227 flag = 0 228 if flag == 0: 229 num_get = num_get + [float(num_c)] 230 num_c = "" 231 num_get = num_get + [float(num_c)] 232 return num_get 233 234 # 判断优先级 235 def judge_pri(self, sym_int): 236 i = 0 237 sym_p = [] 238 for sym_jp in sym_int: 239 if sym_jp == '/': 240 sym_p += [40 + i] 241 i += 1 242 elif sym_jp == '*': 243 sym_p += [30 + i] 244 i += 1 245 else: 246 i += 1 247 i = 0 248 for sym_jp in sym_int: 249 if sym_jp == '-': 250 sym_p += [20 + i] 251 i += 1 252 elif sym_jp == '+': 253 sym_p += [10 + i] 254 i += 1 255 else: 256 i += 1 257 return sym_p 258 259 # 等式运算计算细节实现 260 def int_compute(self, num_int, sym_int): 261 sym_p_int = self.judge_pri(sym_int) 262 while sym_p_int != []: 263 sym = int(sym_p_int[0]) 264 if sym >= 40: 265 if num_int[sym - 40 + 1] == 0: 266 return -1 267 num_int[sym - 40] /= num_int[sym - 40 + 1] 268 num = num_int[sym - 40: sym - 40 + 1] 269 del num_int[sym - 40 + 1: sym - 40 + 2] 270 sym_int = sym_int[:sym - 40] + sym_int[sym - 40 + 1:] 271 elif sym >= 30: 272 num_int[sym - 30] *= num_int[sym - 30 + 1] 273 num = num_int[sym - 30: sym - 30 + 1] 274 del num_int[sym - 30 + 1: sym - 30 + 2] 275 sym_int = sym_int[:sym - 30] + sym_int[sym - 30 + 1:] 276 elif sym >= 20: 277 num_int[sym - 20] -= num_int[sym - 20 + 1] 278 num = num_int[sym - 20: sym - 20 + 1] 279 if num[0] < 0: 280 return -1 281 del num_int[sym - 20 + 1: sym - 20 + 2] 282 sym_int = sym_int[:sym - 20] + sym_int[sym - 20 + 1:] 283 elif sym >= 10: 284 num_int[sym - 10] += num_int[sym - 10 + 1] 285 num = num_int[sym - 10: sym - 10 + 1] 286 del num_int[sym - 10 + 1: sym - 10 + 2] 287 sym_int = sym_int[:sym - 10] + sym_int[sym - 10 + 1:] 288 sym_p_int = self.judge_pri(sym_int) 289 return float(num[0]) 290 291 # 等式运算 292 def compute_c(self, e1): 293 num_int = float() 294 num_int = self.filt_num(e1) 295 sym_int = self.filt_sym(e1) 296 flag = self.int_compute(num_int, sym_int) 297 if flag < 0: 298 return 'f' 299 else: 300 return str(flag) 301 302 # 将等式中括号里面的等式提取出来 303 def judge_bracket(self, equ_j): 304 left = equ_j.rfind('(') 305 right = equ_j.find(')', left) 306 e1 = equ_j[left + 1:right] 307 c1 = self.compute_c(e1) 308 if c1 == 'f': 309 return False 310 equ_j = equ_j[0:left] + str(c1) + equ_j[(left + len(c1)):] 311 equ_j = equ_j[0: left + len(str(c1))] + equ_j[right + 1:] 312 return equ_j 313 314 def math_compute(self, equation): 315 equ_m = equation 316 while equ_m.find('(') != -1: 317 if equ_m.find('(') != -1: 318 equ_m = self.judge_bracket(equ_m) 319 if not equ_m: 320 break; 321 else: 322 break 323 if not equ_m: 324 return 0 325 elif equ_m.find('+') != -1 or equ_m.find('-') != -1 or equ_m.find('*') != -1 or equ_m.find('/') != -1: 326 val = self.compute_c(equ_m) 327 if val == 'f': 328 return 0 329 else: 330 return 1 331 else: 332 return 1 333 334 335 class Judge: 336 '判断Exercises 和 Answers.txt ,并返回处理结果' 337 338 def __init__(self, FileName, FilenameAns): 339 self.user_file = FileName 340 self.standAns_file = FilenameAns 341 self.judge_ans(self.user_file, self.standAns_file) 342 343 def judge_ans(self, user_ans, stand_ans): 344 user_a = open(user_ans, 'r') 345 std_a = open(stand_ans, 'r') 346 i = 0 347 c_sum = [] 348 e_sum = [] 349 while 1: 350 equa_u = user_a.readline() 351 equa_s = std_a.readline() 352 if not equa_u: 353 break 354 ind = equa_u.rfind('=') 355 if equa_u[ind + 1:].strip() == equa_s.strip(): 356 i += 1 357 c_sum += [i] 358 else: 359 i += 1 360 e_sum += [i] 361 print("Correct: ", len(c_sum), c_sum) 362 print("Wrong: ", len(e_sum), e_sum) 363 364 365 if options.Numbers and options.Range and options.ProExFile: 366 '生成Numbers条有负数结果的算式, 再将其标准化(去除中间过程有负数结果的算式以及/后面有0的非法算式), 输出文件是StandExercises.txt' 367 fileE = Genera(options.Numbers, options.Range) 368 fileStand = Verify(fileE.filename) 369 370 if options.Numbers and options.Range and options.ProExFile and options.AnsFile: 371 '生成Numbers条有负数结果的算式, 再将其标准化(去除中间过程有负数结果的算式以及/后面有0的非法算式), 输出文件是StandExercises.txt' 372 fileE = Genera(options.Numbers, options.Range) 373 fileStand = Verify(fileE.filename) 374 fileA = Answer(options.AnsFile) 375 376 if options.AnsFile and not options.Numbers: 377 '回答-a后面的filename题目文件,并输出结果到Answers.txt文件' 378 fileA = Answer(options.AnsFile) 379 380 if options.ProExFile and options.Numbers and options.Range and not options.AnsFile: 381 '生成Numbers条有负数结果的算式, 生成文件是Exercises.txt' 382 fileE = Genera(options.Numbers, options.Range) 383 384 if options.JudgeFile and not options.Numbers and not options.Range and not options.ProExFile: 385 '-j 接一个用户的答案文件, 并将其和标准答案文件Answers.txt比较' 386 FileA = Judge(options.JudgeFile, "Answers.txt")
测试运行:




def hash(self,string): # 获取算式符数目 fuhao = re.finditer('[+\-*÷]', string) i = -1 for match in fuhao: i = i + 1 # 获取算式结果 s = string.replace(' ', '') t = re.search('=', s).end() s = int(s[t:]) return (s % 10) + (i * 10) # s%10表示算式结果模10, i*10表示符号位, 如22则表示三个符号且算式结果个位数是2 11则表示二个符号且算式结果个位数是1
1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3 import re 4 num = 30 5 6 7 # 一个数据节点 8 class Node(object): 9 def __init__(self, data): 10 self.data = data 11 self.next_node = None 12 13 def set_next(self, node): 14 self.next_node = node 15 16 def get_next(self): 17 return self.next_node 18 19 def get_data(self): 20 return self.data 21 22 def data_equals(self, data): 23 return self.data == data 24 25 26 class HashTable(object): 27 def __init__(self): 28 self.value = [None] * num 29 30 def hash(self,string): 31 # 获取算式符数目 32 fuhao = re.finditer('[+\-*÷]', string) 33 i = -1 34 for match in fuhao: 35 i = i + 1 36 # 获取算式结果 37 s = string.replace(' ', '') 38 t = re.search('=', s).end() 39 s = int(s[t:]) 40 return (s % 10) + (i * 10) # s%10表示算式结果模10, i*10表示符号位, 如22则表示三个符号且算式结果个位数是2 11则表示二个符号且算式结果个位数是1 41 42 def insert(self, data): 43 # if self.search(data): 44 # return True 45 46 i = self.hash(data) 47 node = Node(data) 48 if self.value[i] is None: 49 self.value[i] = node 50 return True 51 else: 52 head = self.value[i] 53 while head.get_next() is not None: 54 head = head.get_next() 55 head.set_next(node) 56 return True 57 58 def search(self, data): 59 i = self.hash(data) 60 if self.value[i] is None: 61 return False 62 else: 63 head = self.value[i] 64 while head and not head.data_equals(data): 65 head = head.get_next() 66 if head: 67 return head 68 else: 69 return False 70 71 def delete(self, data): 72 if self.search(data): 73 i = self.hash(data) 74 if self.value[i].data_equals(data): 75 self.value[i] = self.value[i].get_next() 76 else: 77 head = self.value[i] 78 while not head.get_next().data_equals(data): 79 head = head.get_next() 80 head.set_next(head.get_next().get_next()) 81 return True 82 else: 83 return False 84 85 def echo(self): 86 i = 0 87 for head in self.value: 88 print (str(i) + ':\t'), 89 if head is None: 90 print (None), 91 else: 92 while head is not None: 93 print (str(head.get_data()) + ' ->'), 94 head = head.get_next() 95 print (None), 96 print ('') 97 i += 1 98 print("") 99 100 # 101 # 1. 4÷86 = 12 102 # 2. 63÷16÷46*56 = 23 103 # 3. 99+38-59 = 12 104 # 4. 74-50 = 23 105 # 5. 52+47+34+4 = 24 106 # 6. 49*99 = 3 107 # 7. 4÷20 = 4 108 # 8. 1/86*78 = 5 109 110 111 if __name__ == '__main__': 112 hashTable = HashTable() 113 hashTable.insert("4÷86 = 12") 114 hashTable.insert("4÷86 = 12") 115 hashTable.insert("2. 63÷16÷46*56 = 23") 116 hashTable.insert("74-50 = 23") 117 hashTable.insert("8. 1/86*78 = 5") 118 hashTable.echo() 119 # hashTable.delete(11) 120 hashTable.echo()
合作编程日志
2018-09-18 20:47:12 实现生成并写入文件,相关代码上传到Github

2018-09-20 22:11:29

beng le !
2018-09-23 10:33:53
继续调整思路。已经用正则表达式对字符串进行分割运算实现了多个符号存在时候的运算优先级顺序,但是在生成输出结果的时候遇到困难,解决方法是从Exercises.txt里面依次读取每一行,并对每一行进行运算后得出一个关于结果的标准CONTEXT字符串,再把CONTEXT字符串一次性写入Answers.txt中。此种做法1.可以计算任意符合要求的.txt文件,2. 利用CONTEXT一次性写入,极大优化了程序

2018-09-26 23:39:33
小组讨论和分析,全部重写算式生成函数,以及重写判断负数的算法

2018-09-28 16:04:17
在已有功能函数的基础上全部重写。因为团队合作中各种函数传参和处理没有讨论好。并且感谢俊豪同学及时提出问题,我已经写出的函数存在很多缺漏,以及有部分函数未按题目要求编写。/哭泣
合作心得:
昆乘: 合作过程中还是有非常非常多问题, 首先因为大家有选修课, 共同编程的时间并不多,其次是软件工程项目的时间计划没有做, 前面我已经实现了生成和计算然后就丢下了, 最后两天要提交了的时候才发现原来还有很多很多功能没实现. 然后最后赶进度, 函数还有很多很多值得改善的地方都没有做好. 两人小组的时间分配实在做得太差. 没有约定好哪个函数在哪个时间要编写出来, 哪个类什么时候结合, 哪个函数如何测试和优化 都没有计划出来. 因为没有提前合作构思和安排好各个类各个函数的接口, 导致所有函数有两次重写. 很多合作 和 时间计划相关的事情值得反思. 最大的收获明确使用各个类与功能并包装函数, 花了几个小时进行了性能优化, 觉得性能优化很有意思! 虽然还有一些函数还没优化. 编程能力还需要继续提升,算法和数据结构等也要重温.
俊豪: 合作一起同做一个项目比起一个人独自做相比较来说还更累一点,然而,对于存在问题的查找也更加深入。整个过程当中,有过争执,对于分数答案的一个生成两个人有不同的想法,昆乘想用正则表达式,而我觉得才用公倍数乘以有除号存在等式,而最终,因为我的算法有很大的bug,最终才用他的;除了争执,还有过讨论,一开始昆乘尝试一个人写生成函数时,在两人还没开始讨论的情况下,算法考虑不周全,比如,没有生成括号。最后两个人通过一起讨论,对需求进行一步步分析,最终得到一个比较完整周全的方案。整个过程下来,让我感觉到了两个人一起结对编程的不容易,合作本来是为了更好的编程,而不合理的合作却又会使得编程更加困难复杂。讨论沟通是整个过程中最为重要的事,否则会两人极其容易产生分歧,产生分歧时沟通更是需要,不然项目将很难做下去。
总的来说这是一次太匆忙的项目:




浙公网安备 33010602011771号