教学需求:
? ? ? 在前一篇X以内数字分合题里,阿夏通过“列式题导出txt——txt转docx——清除docx空行——调整文档样式另存——删除过渡文件”的方式把《x以内加减法题》直接生成打印用docx。这条路径相当繁琐复杂,转换代码非常冗长。虽然费了两天时间,实现了列表直接导成docx的目标,但阿夏还是感觉——一定有更简单的方法。
? ? ? 机缘巧合下,在CSDN里看到了一篇这篇文章,用两行代码,就把列表数据导入docx?,测试后阿夏不得不感慨——?原来编程导出是这么简单!!!
用python编写习题自动生成工具_编程亿直爽的博客-CSDN博客用到了两个库:random、docx# coding=utf-8'''习题自动生成工具自动生成数学练习题,包含加减乘除,不规定数值范围,由传入的参数(10:10以内;100:100以内)决定。要求1:输入:生成习题数量N,习题范围:M;输出:将生成的习题保存到question(word格式)中,对应的答案保存到answer(word格式)中。'''import randomimport docxN = int(input("请输入需要生成的题的数量:\n"))M = int(https://blog.csdn.net/qq_58153224/article/details/120655487
难题破解:
为了把“马先生的不重复加减法代码”套用上去,阿夏又花费了两天时间解决各种问题,学习的过程中,逐渐理解“列表=[]”到底有什么用、双列表里一大段连在一起的数学题怎么分开(遍历)、怎样批量多份又确保每份里面都有不重复的题目(添加到新列表)?也对word样式生成有初步了解。
(1)批量多份?
实验后,把循环多份的代码添加在数学题代码的最前面,比如让“selectList”的随机循环5次40题。shuffle 确保每次循环的40提结果排序都不同。
检验:把红、黄、绿 三套题目答案导入excel排序测试
?excel排序后论证:每页每套40题的排序不同(AB卷)但最终的题目种类都是一样的。
?
把循环5次的所有题目200题,全部存入alltopic ,这个列表里面就有固定顺序的40+40+40+40+40题。由于40题正好分布一页(word样式设置过了)这样每页上的题目都是排序不同,但内容相同的题目
??????b
(2)连在一起的整合题
把5以内题目40题批量5次后,阿夏发现无论终端显示还是word里,都是题目连在一起的,没有地方写答案,不分段根本看不清题目。
?
?经过反复测试修改
效果:每行都分段了。 一套题目,一套题目+答案,两套内容相同:
题卡题目
?答案
?(3)页码(很重要 很重要)
搜索后发现无法用代码生成批量学号,因此调用了一个“页码.docx”的模板
?只要设置“页脚的页码”其他参数默认原始。
代码运用
(1)复制代码:(先在d:\test下新建一个“页码.docx”,里面的页脚有页码)
'''
item:大班5以内加减法题不重复打印教具。
项目主要功能:
0.大班5以内加减法题目。
1.5以内不重复加减法题共40题(排除0+0= 0-0=)
2.全部题目保存在5*8的A4纸docx内
3.5以内题目批量多页,每页的40题内容相同,但出现顺序随机。
4.本次生成无答案题目。
5.本题所有答案都是打乱模式 random.shuffle.排序请打开sort注释
'''
'''
重要提示:
1。请在主目录下(我是D:\test)新建一个"页码.docx"文档,随便选一个页码插入页脚中间。其他格式不用调整。
2。请在主目录下(我是D:\test)新建一个"页码.docx"文档,随便选一个页码插入页脚中间。其他格式不用调整。
3。请在主目录下(我是D:\test)新建一个"页码.docx"文档,随便选一个页码插入页脚中间。其他格式不用调整。
否则程序不运行!!!
'''
import time# 间隔线 模块
print('----------------第一部分:数学题生成-----------------')
time.sleep(0.5)
# -*- coding: utf-8 -*-
"""
@author: 马清新
@file: 阿夏修改(20以内加法题、20以内减法题、20以内加减法混合题(最大不重复算式值).py
@time: 2022/3/30 16:36
"""
# 第1部分数学题 模块
import random
from re import X
import time
from async_generator import yield_
# 需要输入数字
hao='加减法题'#这里手动写入,可以改成选择题。
sumMax = int(input('请输入最大数字((≥0)):\n'))# 输入最大值
regNum = int(input('请输入需要的数量:\n'))# 输入需要的数量,如果不重复的100题,只需要10题,这里就只出10题,如果不重复有100题,需要120题,最终也只出最大的100题。
N=int(input('{}以内{},你需要多少份\n'.format(sumMax,hao)))# 如果有10个孩子,就打印10份,或者想给1个孩子做5天,打印5份
# 列表一定要放在这里,才能生成5份的量,放下面只能一份
alltopic=[] # 生成5份题目,的所有“题目”都保存在这里
allanswer=[]# 生成5份题目,的所有“题目+答案”都保存在这里
# X以内数字加减法题生成的代码
for zz in range(N): # 生成多少份题目
# range函数从0开始,这样列表元素和列表索引一致,减轻算法的难度
numList = [x for x in range(0,sumMax+1)]# 建立整数列表,假设SUMMAX=20 sumMax+1等于21 但实际范围就是1-20,确保列表索引和列表元素一致
# resultList列表用于保存最后需求数量的合规算术式
resultList = []# 把“计算结果”保存在这里
# 从列表第2个元素开始到列表最后一个元素进行循环遍历
for x in numList[0:]:# 0等于数字1
# 从列表第x个元素开始到列表最后一个元素进行循环遍历
for y in numList[x:]:
# 加法
if (x == y) and (x + y <= sumMax)and (y != 0): # X或Y两者一个或者两个都不能0。没有0+0,0-0
tempStr = str(x) + ' + ' + str(y) + ' = '
resultList.append((tempStr, (x+y)))
tempStr = str(x) + ' - ' + str(y) + ' = '
resultList.append((tempStr, (x-y)))
#加和减 查找 x + y < 算式最大和的加减法,此处考虑加法交换律,减法中去除了相减为0的情况,因为此处y>x
elif x + y <= sumMax and (y != 0):# 第一位或者第二位都不为0,也就是没有
tempStr = str(x) + ' + ' + str(y) + ' = '
resultList.append((tempStr, (x+y)))
tempStr = str(y) + ' + ' + str(x) + ' = '
resultList.append((tempStr, (x+y)))
tempStr = str(y) + ' - ' + str(x) + ' = '
resultList.append((tempStr, (y-x)))
# 考虑循环后期,x+y会打印算式要求的最大和,但是减法符合算式要求,处于严谨的考虑没有使用else
# 减法 此处可以考虑直接使用else
elif y - x >= 0 and y != 0: # y可能等于x ,答案为0,但没有0-0
tempStr = str(y) + ' - ' + str(x) + ' = '
resultList.append((tempStr, (y-x)))
# elif y - x == 0 :#等数 相加 相减等于0,本题为了凑满A4纸,放弃0+0=0和0-0=0,Ctrl+/ 进行注释
# tempStr = str(y) + ' + ' + str(x) + ' = '#减法类型3 y-x=0
# resultList.append((tempStr, (y+x)))# 带答案的题目,如0+0=0,
# tempStr = str(y) + ' - ' + str(x) + ' = '#减法类型3 y-x=0
# resultList.append((tempStr, (y-x)))# 带答案的题目,如0-0=0,
selectList =[]# 把resultList的答案打乱排序或者正序排序,存入selectList被选择过的列表里
selectList_topic=[] # 把selectList的2项内容合并存入selectList_topic 只存入题目
selectList_answer=[]# 把selectList的2项内容合并存入selectList_topic 存入题目和答案
if regNum > len(resultList):#如果(输入算式的数量)大于(结果列表的数量)#输入题数大于实际需求,就用shuffle洗牌,
print(f'您的需求大于最大算式生成数量!最大生成算式数量为{len(resultList)}') # 加了最大不重复算式统计值,如果输入的题数大于储存结果的列表的数量,列表加LEN
i = len(resultList)# i的数量等于储存结果的resultList列表的数量
for _ in resultList:# 储存结果的列表resultList内部循环跑一次
selectList.append(_) #在“selectList” 里添加 从“resultList“遍历的值
random.shuffle(selectList) #shuffle 洗牌算法,把内部的值打乱,随机排列。
# selectList.sort()#sort 正序排列,
# 问题:只有10以内的能排序, 超过就是1排在10前面,一第一个数字排序,
# 如果用了selectList.sort()这一条,打印的每一页题目都是一模一样的(从小到大排列。等同于word打印X份
# selectList.sort(reverse=True) #从大到小 倒叙排列 5 + 0 = 5 4 + 1 = 5 ……
for _ in selectList: #在随机排列过得selectList里 遍历循环
# 可选打印带答案的和不带答案啊8
print(_[0])# 不带答案
print(f'{_[0]}{_[1]}')# 终端带答案,
selectList_topic.append(_[0]) # 把遍历取的结果(只有前面的题目,没有答案)添加到 selectList_topic里面
selectList_answer.append(f'{_[0]}{_[1]}')# 把遍历取的结果(有题目有答案)添加到 selectList_topic里面
else:#输入题数小于实际需求,代码自动随机抽取,不会排序,
i = regNum
selectList = random.sample(resultList,i)
for _ in selectList:
# 可选打印带答案的和不带答案啊
print(_[0])# 不带答案
print(f'{_[0]}{_[1]}')# 终端带答案,
selectList_topic.append(_[0])# 把遍历取的结果(有题目,没有答案)添加到 selectList_topic里面
# random.shuffle(selectList_topic)
selectList_answer.append(f'{_[0]}{_[1]}') #把遍历取的结果(有题目有答案)添加到 selectList_topic里面
# random.shuffle(selectList_answer)
# 验证生成算式数量70
print(f'共生成不重复的纯加法算式的题目数量{len(selectList)}')# 选择列表selectList的数量
print(f'纯加法最大不重复的算式的限制数量{len(resultList)}')# 结果列表resultList的数量
# 也就是selectList_topic等于5以内共40题(一套题),把这套题目批量多份,此时的题目都是连在一起的
alltopic.append(selectList_topic)
print(alltopic) #这里结果是这种类型[['2 + 3 = ', '2 - 2 = '], ['2 + 1 = ', '3 - 0 = ']]
allanswer.append(selectList_answer)# X页内的所有题目
print(allanswer) #这里结果打印后会变成:2 + 3 = 2 - 2 = 2 + 1 = 全部连在一起,没有分段
alltopic2=[] # 把题目变成一段一段的,不要连在一起,结果存在这里
for j1 in alltopic: #用遍历把双列表里面的数学题提取出来
for j2 in j1: # [[][]]有两组括号,遍历两次
print(j2)
alltopic2.append(j2) # 把遍历后的单条题目 添加到alltopic2题目汇总列表里
allanswer2=[]# 把题目变成一段一段的,不要连在一起 结果存在这里
for k1 in allanswer: #用遍历把双列表里面的数学题+答案提取出来
for k2 in k1: # [[][]]有两组括号,遍历两次
print(k2)
allanswer2.append(k2) # 把遍历后的单条题目 添加到alltopic2题目答案汇总列表里
print('-------------------第一部分 完成---------------------')
time.sleep(0.5)
print('------------第二部分:"幼儿题目纸”导入docx--------------')
time.sleep(0.5)
# 第2部分word模板样式 模块
import docx
from docx import Document
from docx.shared import Pt
from docx.shared import RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
# s设置基本模板
doc = docx.Document('页码.docx')# 打开带docx模板(这个模板有页脚的页码,阿夏认为页码是必须的)
for k in alltopic2: # 用k 在selectList3的列表值(40题*N)内遍历
# print(k) # 打印遍历的内容
doc.add_paragraph(k) # 把内容按段落输入到doc这个docx文件内
# 上面两行代码来自:CSDN博主「编程亿直爽」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
# 原文链接:https://blog.csdn.net/qq_58153224/article/details/120655487
# 感谢它解决困扰我很久的问题——如何把“终端答案/selectList=[]列表的值 直接保存到docx(不通过TXT转存)”
# 字体这一段一定要再写一次
for paragraph in doc.paragraphs:
for run in paragraph.runs:
run.font.size = Pt(30) # 数字题目字体大小
run.font.bold = False #数字题目字体是否加粗 不加粗,5*8再加粗比较满,压抑了
run.font.name = 'Arial' # 控制是英文时的字体
run.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑') # 控制数字是中文时的字体
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT # 设置数字页眉居中对齐
# paragraph.paragraph_format.line_spacing=2.5 #数字中文字的段行距
paragraph.paragraph_format.line_spacing = Pt(50) #数字段间距
# 设置页眉的内容
hao="加减法"
header = doc.sections[0].header # 获取第一个节的页眉
paragraph = header.paragraphs[0] # 获取页眉的第一个段落
text =paragraph.add_run('{}以内{}-不重复题数-共{}题-(排除0+0,0-0)\n'
'姓名:______________学号:_______________班级:___________分数________ '.format(sumMax,hao,len(resultList))) # 添加页面内容
text.font.size = Pt(20) # 页眉字体大小
text.bold = True # 页眉字体是否加粗
text.font.name = 'Arial' # 控制是英文时的字体
text.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑') # 控制是中文时的字体
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 设置页眉居中对齐
paragraph.paragraph_format.line_spacing=1.5 #页眉中文字的段间距
# 设置主要页边距 5
from docx.shared import Cm # 导入cm模块
doc.sections[0].top_margin = Cm(1)# sections[1]是第二节=第二页 上边距
doc.sections[0].bottom_margin = Cm(1)# sections[1]是第二节=第二页 下边距
doc.sections[0].left_margin = Cm(1) # sections[1]是第二节=第二页 左边距
doc.sections[0].right_margin = Cm(1.5)# sections[1]是第二节=第二页 右边距
# 设置其他页边距
doc.sections[0].gutter=Cm(0)# sections[1]是第二节=第二页 装订线 默认为0 左
doc.sections[0].header_distance=Cm(0.8)# sections[1]是第二节=第二页 页眉边距
doc.sections[0].footer_distance=Cm(1.3)# sections[1]是第二节=第二页 页脚边距
# 装订线还有一个位置属性,暂时未发现如何设置,默认为左,如果需求设置成右,可以建个模板docx文档导入。
# 设置纸张方向和大小 LANDSCAPE=横 PORTRAIT纵 默认信纸 纵
from docx.shared import Cm # 导入CM #
from docx.enum.section import WD_ORIENTATION # 导入纸张方向
doc.sections[0].page_height = Cm(21) # 设置A4纸的高度
doc.sections[0].page_width = Cm(29.7) # 设置A4纸的宽
doc.sections[0].orientation = WD_ORIENTATION.LANDSCAPE # 设置纸张方向为横向 L
# 设置分栏 如果不要,就把数字该为为1
from docx.oxml.ns import qn
doc.sections[0]._sectPr.xpath('./w:cols')[0].set(qn('w:num'), '5') #把第二节页设置为2栏
# 设置页眉和页脚
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT# 导入文本居中 居左、居右
from docx.shared import Pt
# 基本模板
doc.save('{}以内{}-不重复题数-共{}题-(排除0+0,0-0)-共{}页.docx'.format(sumMax,hao,len(resultList),N))
print('-------------------第二部分 题目纸 完成-----------------')
time.sleep(0.5)
print('--------------第三部分:“教师答案纸”导入docx---------------')
time.sleep(0.5)
# 设置基本模板
doc = docx.Document('页码.docx')# 打开带页脚的docx模板(样板要输入数据 才能被保存,)
# “题目docx”和“题目+答案word”都需要同样的格式设置,把设置部分做一个函数体,便于调用。
for l in allanswer2: # 用k 在selectList3的列表值(40题*N)内遍历
# print(k) # 打印遍历的内容
doc.add_paragraph(l) # 把内容按段落输入到doc这个docx文件内
# CSDN博主「编程亿直爽」
# 字体这一段一定要再写一次
for paragraph in doc.paragraphs:
for run in paragraph.runs:
run.font.size = Pt(30) # 数字题目字体大小
run.font.bold = False #数字题目字体是否加粗 不加粗,5*8再加粗比较满,压抑了
run.font.name = 'Arial' # 控制是英文时的字体
run.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑') # 控制数字是中文时的字体
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT # 设置数字页眉居中对齐
# paragraph.paragraph_format.line_spacing=2.5 #数字中文字的段行距
paragraph.paragraph_format.line_spacing = Pt(50) #数字段间距
# 设置页眉的内容
hao="加减法"
header = doc.sections[0].header # 获取第一个节的页眉
paragraph = header.paragraphs[0] # 获取页眉的第一个段落
text =paragraph.add_run('{}以内{}-不重复题数-共{}题-(排除0+0,0-0)-(答案)\n'
'姓名:______________学号:_______________班级:___________分数________ '.format(sumMax,hao,len(resultList))) # 添加页面内容
text.font.size = Pt(20) # 页眉字体大小
text.bold = True # 页眉字体是否加粗
text.font.name = 'Arial' # 控制是英文时的字体
text.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑') # 控制是中文时的字体
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 设置页眉居中对齐
paragraph.paragraph_format.line_spacing=1.5 #页眉中文字的段间距
# 设置主要页边距 5
from docx.shared import Cm # 导入cm模块
doc.sections[0].top_margin = Cm(1)# sections[1]是第二节=第二页 上边距
doc.sections[0].bottom_margin = Cm(1)# sections[1]是第二节=第二页 下边距
doc.sections[0].left_margin = Cm(1) # sections[1]是第二节=第二页 左边距
doc.sections[0].right_margin = Cm(1.5)# sections[1]是第二节=第二页 右边距
# 设置其他页边距
doc.sections[0].gutter=Cm(0)# sections[1]是第二节=第二页 装订线 默认为0 左
doc.sections[0].header_distance=Cm(0.8)# sections[1]是第二节=第二页 页眉边距
doc.sections[0].footer_distance=Cm(1.3)# sections[1]是第二节=第二页 页脚边距
# 装订线还有一个位置属性,暂时未发现如何设置,默认为左,如果需求设置成右,可以建个模板docx文档导入。
# 设置纸张方向和大小 LANDSCAPE=横 PORTRAIT纵 默认信纸 纵
from docx.shared import Cm # 导入CM #
from docx.enum.section import WD_ORIENTATION # 导入纸张方向
doc.sections[0].page_height = Cm(21) # 设置A4纸的高度
doc.sections[0].page_width = Cm(29.7) # 设置A4纸的宽
doc.sections[0].orientation = WD_ORIENTATION.LANDSCAPE # 设置纸张方向为横向 L
# 设置分栏 如果不要,就把数字该为为1
from docx.oxml.ns import qn
doc.sections[0]._sectPr.xpath('./w:cols')[0].set(qn('w:num'), '5') #把第二节页设置为2栏
# 设置页眉和页脚
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT# 导入文本居中 居左、居右
from docx.shared import Pt
doc.save('{}以内{}-不重复题数-共{}题-(排除0+0,0-0)-共{}页-(答案).docx'.format(sumMax,hao,len(resultList),N))
print('-------------------第三部分“答案纸”完成---------------------')
time.sleep(0.5)
print('---------------请到D盘test下查找---------------------')
time.sleep(0.5)
运行过程:
(一)运行
?(二)输入三类数字
?(三)终端结果??及 文件位置
?(四)文本效果
题卡效果(无答案)?
答案纸效果(题目+答案)
题目整体展示:题目顺序打乱,难以抄袭
其他说明
1.本代码设置过docx格式,最适合5以内加减法题,正好40题一页。
2.如果用10以内,也是可以使用的,因为每页内的40题不会重复。
(1)幼儿人数:28人为例,10以内,输入大于130的数字140,并要28份
?最终获得91页共3640题,此时只需要打印1-28页即可。每位孩子一张A4,A4每页上的题目确保不重复
?(1)幼儿人数:1人为例,实际只需要打印1份就可以了,保证不重复练习。
?
?成效分析:
1.从随机重复数量到确定最大数量(确定性):
大部分的编程生成数学题都是随机生成,幼儿反馈发现每页A4题目上出现连续的重复题,感谢马先生的代码,排除了重复,获得了最大不重复的X以内加减法题目。
2.从TXT手动制表到自动导入docx(快捷性)
这是第二种将代码输出结果(列表值)导入docx的方法,比第一种的多转换(TXT转word,删除过渡文件)更方便快捷(这才是最原始的把数据写入docx段落方法)。
3.从生搬硬套借鉴到真实理解用途(技术性)
这四天的研究,让阿夏对前期马先生设计的各类教具代码有了初步的认同感,特别是a=[]。b.append(a)的意义,通过反复嵌套,定义新的字母使用[]列表数组添加新值。还有遍历循环,提取列表里的值、或者把值逐一写入docx每一段等等。
4.从随机打乱题目到正序排列题目(规律性)
如果将随机打乱题目的random.shtffle()改成selectList.sort()?正序排列,就可以把题目以左侧第一个数字,从小到大的顺序排列出来,这种规律性也是教学中的一种方式,可以让幼儿掌握更多的数字规律。(但是超过10就,会出现1+2= 排在10-2=的前面,提取加减符号前面的数字进行排序,研究中……))
?(ps:sort排序时。无论输出多少份,每页内容都是从小到大排列。只需要批量一份,打印机设置打印X份即可。)
while True:
????????print(learn)
|