课堂派题库格式转换程序
一、背景
這個(gè)學(xué)期開設(shè)的Java程序設(shè)計(jì)課程,需要用課堂派來(lái)簽到和平常練習(xí),老師苦于課堂派后臺(tái)的課堂測(cè)試需要人工填入題目,好在課堂派運(yùn)行符合格式的題目直接從word文檔中導(dǎo)入,于是讓我們來(lái)寫一個(gè)小程序來(lái)實(shí)現(xiàn)這個(gè)格式轉(zhuǎn)換。老師用的源題庫(kù)是有特殊格式的,這樣我們就可以通過(guò)一些特殊的標(biāo)記來(lái)實(shí)現(xiàn)對(duì)源題庫(kù)的讀取,我最開始使用C++來(lái)實(shí)現(xiàn)的,后來(lái)補(bǔ)充的Java的版本。該程序主要是對(duì)string的操作,二者之中有許多相同的函數(shù)方法,但具體的寫法卻有所不同,同時(shí)Java的限制數(shù)組越界、不能更改String的一些特點(diǎn),也讓有些頭疼,Java寫的還是太少了!
二、格式要求
源題庫(kù)樣例:
目標(biāo)題庫(kù)格式:
具體要求:
1.第一行為題干,中間不要換號(hào)(課堂派后臺(tái)只能識(shí)別一行題干),可以加題號(hào),也可以不加題號(hào),編寫程序時(shí)可以通過(guò)一個(gè)選項(xiàng)開關(guān)讓使用者決定是否需要保留題號(hào)。
2.答案要寫在題目開頭或者結(jié)尾,用括號(hào)括起來(lái),大小寫括號(hào)均可。在題干末尾添加本題的類型和分?jǐn)?shù),用大括號(hào)括起來(lái)。題目的類型需要通過(guò)答案的個(gè)數(shù)自己判斷,題目的分?jǐn)?shù)需要程序的使用者來(lái)輸入。
3.題干之后是選項(xiàng)行,選項(xiàng)中不要空行,一個(gè)選項(xiàng)是單獨(dú)的一行,選項(xiàng)字母需要英文大寫。
4.每一道題與下一道題目之間需要空三行作為標(biāo)志。
5.源題庫(kù)中的有些題目可能會(huì)有解析,這里解析不需要提取處理。
6.源題庫(kù)中出現(xiàn)的Chapter和Section的內(nèi)容可以輸出到控制臺(tái),目標(biāo)文件中不要出現(xiàn)。
三、C++源代碼
#include<fstream> //ifstream
#include<iostream>
#include<string>
#include<map>
using namespace std;
struct subject
{
int id;//題目序號(hào)
int type;//題目類型
string stem;//題干內(nèi)容
map<string,string>options;//選項(xiàng)與答案的map鍵值對(duì)
int num;//選項(xiàng)個(gè)數(shù)
string score;//題目分?jǐn)?shù)
string key;//答案
string analysis;//有些題目需要解析
};
int main()
{
string s,temp;
string path;
ofstream outf;
ifstream inf;
int cnt=0;//記錄題目的個(gè)數(shù)
int num1=0;//單選題個(gè)數(shù)
int num2=0;//多選題個(gè)數(shù)
int flag=0;//默認(rèn)保留原題號(hào)
char select;//是否保留題號(hào)的選項(xiàng)
string score;
struct subject sbj[100];
string::size_type pos(0);
cout << "請(qǐng)輸入需要轉(zhuǎn)換的文本文件路徑:(例:C://in.txt)" <<endl;
cin >> path;
if(inf)
{
cout << "打開文本文件成功!" <<endl;
}
else
{
cout << "打開文本文件失敗!" <<endl;
}
inf.open(path);//打開文本文件I://chapter1.txt
cout << "請(qǐng)輸入轉(zhuǎn)換輸出的文本文件路徑:(例:C://out.txt)" <<endl;
cin >> path;
outf.open(path);//需要寫入的文本文件
//目標(biāo)文本的讀取
cout << "轉(zhuǎn)換完成后的題目是否保留原題號(hào)?(y/n)" <<endl;
while(1)
{
cin >> select;
if(select=='y')
{
flag=1;
break;
}
else if(select=='n')
{
flag=0;
break;
}
else
{
cout << "只能輸入y或n,請(qǐng)重新輸入!" <<endl;
}
}
while (getline(inf, s))
{
if(s.substr(0,7)=="Chapter")
{
cout<<s<<endl;
}
else if(s.substr(0,7)=="Section")
{
cout<<s<<endl;
}
//提取選項(xiàng)信息
else if(s.substr(0,1)>="0"&&s.substr(0,1)<="9") //提取題干信息
{
cnt++;
if(flag==1)
{
pos =s.find(".");
temp=s.substr(pos+1,s.length()-pos);
sbj[cnt].stem = temp;//保存題干內(nèi)容
}
else if(flag==0)
{
sbj[cnt].stem = s;
}
sbj[cnt].id = cnt;
sbj[cnt].num = 0;
while (getline(inf, s))
{
if(s.substr(0,4)=="Key:")//提取答案信息
{
temp=s.substr(4,s.length()-4);
pos =temp.find(" ");
sbj[cnt].key=temp.substr(0,pos);
cout<<sbj[cnt].key<<endl;
for(int i=0; i<sbj[cnt].key.length(); i++)//答案替換為大寫字母
{
if(sbj[cnt].key[i]>='a'&&sbj[cnt].key[i]<='z')
{
sbj[cnt].key[i]=sbj[cnt].key[i]-32;
}
}
pos=sbj[cnt].key.length()-1;
if(temp.length()>sbj[cnt].key.length())
{
sbj[cnt].analysis=temp.substr(pos,temp.length()-pos);
}
}
else if((s[0]>='a'&&s[0]<='z')||(s[0]>='A'&&s[0]<='Z'))//提取選項(xiàng)信息
{
if(s[0]>='a'&&s[0]<='z')//選項(xiàng)是小寫字母,轉(zhuǎn)為大寫字母
{
s[0]=s[0]-32;
}
sbj[cnt].options.insert(pair<string,string>(s.substr(0,1),s.substr(2,s.length()-2)));//保存選項(xiàng)
sbj[cnt].num++;
}
else if(s.substr(0,1)=="#")//分隔符,下一道題
{
break;
}
}
cout<<"第"<<cnt<<"道題識(shí)別成功!!"<<endl;
cout<<sbj[cnt].stem<<endl;
cout<<"答案:"<<sbj[cnt].key<<endl<<endl;
}
}
cout<<"讀取文本文件成功!"<<endl;
//目標(biāo)文本的處理
for(int i=1; i<=cnt; i++)
{
pos=0;
sbj[i].stem.insert(pos,"( "+sbj[i].key+" )");//答案的插入
if(sbj[i].key.length()==1)
{
sbj[i].stem=sbj[i].stem+"[單選題]";
num1++;
}
else if(sbj[i].key.length()>1)
{
sbj[i].stem=sbj[i].stem+"[多選題]";
num2++;
}
}
cout<<"檢測(cè)到單選題"<<num1<<"道,多選題"<<num2<<"道"<<endl;
cout<<"請(qǐng)輸入題目的分?jǐn)?shù):[1~100]"<<endl;
cin>>score;
for(int i=1; i<=cnt; i++)
{
sbj[i].score=score;
sbj[i].stem=sbj[i].stem+"["+score+"分]";
}
for(int i=1; i<=cnt; i++)//文本寫入
{
outf<<sbj[i].stem<< '
';//寫入題干
map<string,string>::iterator iter;
for(iter = sbj[i].options.begin(); iter != sbj[i].options.end(); iter++)
{
outf<<iter->first<<"."<<iter->second<< '
';//寫入選項(xiàng)
}
outf<< '
'<< '
'<< '
';
}
inf.close();
outf.close();
cout<<"文本轉(zhuǎn)換完成!"<<endl;
return 0;
}
四、Java源代碼
import java.io.*;
import java.util.*;
//import java.util.Map;
//import java.util.HashMap;
class subject
{
int id;//題目序號(hào)
int type;//題目類型
int num;//選項(xiàng)個(gè)數(shù)
String stem;//題干內(nèi)容
int score;//題目分?jǐn)?shù)
String key;//答案
String analysis;//有些題目需要解析
Map<String,String>options=new LinkedHashMap<String,String>();//map映射,LinkedHashSet正序輸出
public subject()//構(gòu)造函數(shù)
{
id = 0;
type = 1;
num = 0;
score =1;
stem = null;
key = null;
analysis = null;
}
}
public class Main {
public static void main(String args[]) {
int cnt = 0;
int num1=0;//單選題個(gè)數(shù)
int num2=0;//多選題個(gè)數(shù)
int flag=0;//默認(rèn)保留原題號(hào)
char select;//是否保留題號(hào)的選項(xiàng)
int score;
String pathname_in;
String pathname_out;
Scanner in=new Scanner(System.in);
subject [] sbj;
sbj = new subject[1000];
for(int i=0;i<sbj.length;i++){
sbj[i]= new subject();
}
//String pathname = "I://chapter1.txt";
System.out.println("請(qǐng)輸入需要轉(zhuǎn)換的文本文件路徑:(例:C://in.txt)");
pathname_in =in.nextLine();
System.out.println("請(qǐng)輸入轉(zhuǎn)換輸出的文本文件路徑:(例:C://out.txt)");
pathname_out =in.nextLine();
System.out.println("轉(zhuǎn)換完成后的題目是否保留原題號(hào)?(y/n)");
while(true){
select =in.nextLine().charAt(0);
if(select=='y'){
flag=1;
break;
}
else if(select=='n'){
flag=0;
break;
}
else
{
System.out.println("只能輸入y或n,請(qǐng)重新輸入!");
}
}
try (FileReader reader = new FileReader(pathname_in);
BufferedReader br = new BufferedReader(reader) // 建立一個(gè)對(duì)象,它把文件內(nèi)容轉(zhuǎn)成計(jì)算機(jī)能讀懂的語(yǔ)言
) {
String line;
//網(wǎng)友推薦更加簡(jiǎn)潔的寫法
while ((line = br.readLine()) != null) {
if(line.length()==0){
continue;
}
else if(line.substring(0,7).equals("Chapter")){
System.out.println(line);
}
else if(line.substring(0,7).equals("Section")){
System.out.println(line);
}
else if((line.charAt(0)>='0')&&(line.charAt(0)<='9')){
cnt++;
String temp;
int pos;
if(flag==1){
pos =line.indexOf('.');
temp=line.substring(pos+1,line.length());
sbj[cnt].stem = temp;//保存題干內(nèi)容
}
else if(flag==0){
sbj[cnt].stem = line;
}
sbj[cnt].id=cnt;
sbj[cnt].num=0;
while ((line = br.readLine()) != null) {
System.out.println(line);
if(line.length()==0){
continue;
}
else if(line.charAt(0)=='#'){
break;//分隔符
}
else if(line.length()<=4)
{
continue;
}
else if(line.substring(0,4).equals("Key:")){
temp = line.substring(4,line.length());//答案和解析的內(nèi)容
pos = temp.indexOf(' ');
if(pos==-1){//沒有解析說(shuō)明
sbj[cnt].key= temp.toUpperCase();//寫回
System.out.println(sbj[cnt].key);
}
else {
sbj[cnt].key=temp.substring(0,pos);//答案選項(xiàng)
sbj[cnt].key=sbj[cnt].key.toUpperCase();//寫回
pos=sbj[cnt].key.length()-1;
if(temp.length()>sbj[cnt].key.length()){
sbj[cnt].analysis=temp.substring(pos,temp.length()-pos);
}
}
}
else if(((line.charAt(0)>='a'&&line.charAt(0)<='z')||(line.charAt(0)>='A'&&line.charAt(0)<='Z'))&&(line.charAt(1)=='.')){
String opt = line.substring(0,2);//選項(xiàng)
String detail = line.substring(2,line.length());//選項(xiàng)描述
sbj[cnt].options.put(opt,detail);
sbj[cnt].num++;
}
else
{
continue;
}
}
System.out.println("第"+cnt+"道題識(shí)別成功!!");
System.out.println(sbj[cnt].stem);
System.out.println("答案:"+sbj[cnt].key+"
");
}
else
{
continue;
}
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("讀取文本文件成功!");
for(int i=1;i<=cnt;i++){
sbj[i].stem="( "+sbj[i].key+" )"+sbj[i].stem;
if(sbj[i].key.length()==1){
sbj[i].stem=sbj[i].stem+"[單選題]";
num1++;
}
else if(sbj[i].key.length()>1){
sbj[i].stem=sbj[i].stem+"[多選題]";
num2++;
}
}
System.out.println("檢測(cè)到單選題"+num1+"道,多選題"+num2+"道");
System.out.println("請(qǐng)輸入題目的分?jǐn)?shù):[1~100]");
score =in.nextInt();
for(int i=1; i<=cnt; i++){
sbj[i].score=score;
sbj[i].stem=sbj[i].stem+"["+score+"分]";
}
try {
File writeName = new File(pathname_out); // 相對(duì)路徑,如果沒有則要建立一個(gè)新的output.txt文件
writeName.createNewFile(); // 創(chuàng)建新文件,有同名的文件的話直接覆蓋
try (FileWriter writer = new FileWriter(writeName);
BufferedWriter out = new BufferedWriter(writer)
) {
for(int i=1; i<=cnt; i++){//文本寫入
out.write(sbj[i].stem+"
");
Iterator<Map.Entry<String, String>> entries = sbj[i].options.entrySet().iterator();
while(entries.hasNext()){
Map.Entry<String, String> entry = entries.next();
out.write(entry.getKey()+entry.getValue()+"
");
}
out.write("
"+"
"+"
");
}
out.flush(); // 把緩存區(qū)內(nèi)容壓入文件
}
} catch (IOException e){
e.printStackTrace();
}
System.out.println("文本轉(zhuǎn)換完成!");
}
}
五、遇到的一些問(wèn)題
1.Java中關(guān)于HashMap的元素遍歷的順序問(wèn)題
摘自https://www.cnblogs.com/xdp-gacl/p/3558625.html
在使用如下的方式遍歷HashMap里面的元素時(shí)
for (Entry<String, String> entry : hashMap.entrySet()) {
MessageFormat.format("{0}={1}",entry.getKey(),entry.getValue());
}
發(fā)現(xiàn)得到的元素不是按照之前加入HashMap的順序輸出的,這個(gè)問(wèn)題我之前倒是沒有注意過(guò),后來(lái)上網(wǎng)查了一下原因,發(fā)現(xiàn)是:HashMap散列圖、Hashtable散列表是按“有利于隨機(jī)查找的散列(hash)的順序”。并非按輸入順序。遍歷時(shí)只能全部輸出,而沒有順序。甚至可以rehash()重新散列,來(lái)獲得更利于隨機(jī)存取的內(nèi)部順序。
總之,遍歷HashMap或Hashtable時(shí)不要求順序輸出,即與順序無(wú)關(guān)。
Map<String, String> paramMap = new HashMap<String, String>();
可以用java.util.LinkedHashMap 就是按加入時(shí)的順序遍歷了。
Map<String, String> paramMap = new LinkedHashMap <String, String>();
類似的還有 java.util.LinkedHashSet
2.C++中對(duì)字符串中所有指定的子串進(jìn)行替換的函數(shù)
/*
* string& str 源字符串
* const string& old_value 被替換子串
* const string& new_value 替換子串
*/
string& replace_all(string& str,const string& old_value,const string& new_value)//替換函數(shù)
{
while (true)
{
string::size_type pos(0);
if ((pos = str.find(old_value)) != string::npos)
{
str.replace(pos, old_value.length(), new_value);
}
else
{
break;
}
}
return str;
}
總結(jié)
以上是生活随笔為你收集整理的课堂派题库格式转换程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Qt在linux下无法输入中文,Ubun
- 下一篇: linux升级ssh到6.6版本,Cen