毛概答题小助手项目中的关键技术点

一、简介

“毛概答题小助手”是笔者开发的一款辅助学生学习记忆毛概客观题的一款轻量级的桌面端应用程序。该软件可以从特定格式的json文件中提取出题干、选项和答案,并利用程序逻辑来完成判题。

界面

软件的前端页面使用C# + WPF编写,利用C#优雅的语言特性和WPF的Binding机制,可以很好地在前端界面和后端数据之间形成通路;软件的数据(题库)来自正则表达式提取,通过使用特定的正则表达式,可以从整个题目片段中精准地提取出题干等信息。接下来分块解析整个项目中的重点和难点。

二、正则表达式提取

在正则表达式提取这块,主要采用分歩提取的策略,首先从大量题目组成的文本中提取出多个孤立的题目,在根据题目的格式特点来提取题干、选项和答案。在提取孤立的题目时,使用的正则表达式串为:[0-9]\.?(.+?)答案,同时需要注意,需要开启正则表达式的“S模式”,即不匹配新的行,否则会出现无法提取的情况。下面为使用在线网站模拟提取的情况:

提取单个题目

在脚本中,就可以将各个题目转化为对象,进行进一步操作了。接下来是各个题目中答案的提取,这个比较简单:答案[:|:](.*\S)。注意,这一步不需要对单个题目进行提取,而是应该像上一步一样对所有题目提取,否则单个题目的文本中不会包含“答案”字眼。

下一步是选项提取,也相对简单,注意到选项前面都有A-F的标号,所以使用[ABCDEF]\.?([^A-F^\n].*)就可以轻松提取出各个题目的选项。

三、转化为json

提取出的数据还是以python的对象形式存在的,并不能直接使用,所以需要想办法将其持久化为文件的形式。这里笔者第一个想到的就是轻量化的json格式,json文件的表达效率高,并且多种编程语言都有相应的库来处理json文件,比较适合我们的应用场景。当然,也可以自定义一个文件格式来表达题目,这样做可以更好地节约空间,但是制定一个新的文件格式(协议)比较费脑,这里就直接使用json了。

python自带json库来将列表等数据类型转化为json文件,只需要使用json.dump(object)即可,非常方便快捷。当然,在此之前要确定一下数据类型,不同的数据类型转换的json文件格式是不同的。笔者这里将每个单独的题目定义为一个字典,字典有typequestioncandidateanswer四个字段,分别用于表达题目类型(单选、多选、判断),题干、选项、答案。题目类型可以从答案中推断出来。

转化成的json文件

在C#语言中,提取Json需要使用第三方库,笔者使用的NewTonJson这个库来完成的。

四、WPF编写

下面是官方文档对WPF的简介:

WPF 的核心是一个与分辨率无关且基于矢量的呈现引擎,旨在充分利用现代图形硬件。 WPF 通过一套完善的应用程序开发功能对该核心进行了扩展,这些功能包括可扩展应用程序标记语言 (XAML)、控件、数据绑定、布局、二维和三维图形、动画、样式、模板、文档、媒体、文本和版式。 WPF 属于 .NET,因此可以生成整合 .NET API 其他元素的应用程序。

个人对WPF的浅显理解就是WPF是用于图像化界面开发的一个平台,前端使用xaml语言,后端使用C#语言,并使用Binding特性将前后端的数据简洁地联络起来。Binding这个特性是WPF最为人称道的特性,将以往的事件驱动的编程方式变成了数据驱动的编程方式。

笔者个人认为,WPF还是相当简洁的,在编写整个项目的过程中遇到的最大的问题就是对语言不是很熟悉,许多功能不知道如何实现,还好有各大网友和ChatGPT的帮助,让各种问题迎刃而解。

1.CLR对象绑定

遇到的第一个问题就是如何将自己写的CLR对象暴露给前端的xaml,实际上方法是比较多的:

  • 在xaml的资源中声明一个CLR对象,并从后端按名字获取
  • 在后端new一个对象,并将其赋值给前端的DataContext

我选择的是第二种,但是当时遇到一个问题,就是实际运用中我声明了多个类,这么一来就需要为多个DataContext赋值,显得相对麻烦,后来回忆起来,其实应该将这几个类打包成一个新的类,然后赋值给顶层组件的DataContext的。

2.根据数据内容选择前端组件

这个需求理解起来很简单,即如果是单选题就在每个选项前面显示单选按钮(RadioButton),如果是多选题就在每个选项前面显示可以多选的框(CheckBox)。虽然听起来很简单,但是当时不知道如何表达这个需求,找了很多资料都没有解决(但是误打误撞把ListBox这个特性给学习了)。

最终的解决方法是DataTemplate+TemplateSelector,原理就是在资源中声明两个DataTemplate,其中的组件是不同的,分别用于显示单选题和多选题,然后再声明一个TemplateSelector(需要在后端中继承DataTemplateSelector类,并实现相应方法。实现的方法要根据传入的参数来返回相应的DataTemplate,从而在前端有不同的显示效果。

3.类的设计

类的设计这块,在语言方面是相当简单的,无非就是设计一堆属性然后赋值,并套娃。但是实际上设计出符合直觉的、合理的类之间的关系是相对复杂的,特别是WPF又引入了依赖属性的概念,要求实现INotifyOnPropertyChanged接口。

在这个项目中设计的类主要是选项、题目和题目列表,三者的包含范围从小到大。由于笔者自认为最终的设计也不是完美的,所以这里就不展示最终设计的结果了。

五、总结

“毛概答题小助手”第一代原只是为了帮助自己记忆客观题,没想到后来发布后,引起了不错的反响,于是当时下定决心将这个软件完善得更好,帮助更多人。这也算是我大学期间捣鼓出的为数不多的实用小工具吧,当然,和那些大学四年憋出一个独立游戏的大佬还是不能比的。

下面是我从这个项目总结出的心得:

第一点就是要对语言特性非常掌握,否则会写出又臭又长的代码,影响可读性;第二点是代码重构是必然的,不可能在第一次就能写下完美的代码,每一次重构都能让代码的质量上升一个台阶;第三点是编程要持之以恒,三天打鱼两天晒网会严重影响项目的开发进度,有可能第一天写下的代码,过几天就忘了’。


毛概答题小助手项目中的关键技术点
http://zhf-xdu.top/2023/09/04/毛概答题小助手项目中的关键技术点/
作者
周洪锋
发布于
2023年9月4日
许可协议