課堂派題庫格式轉換程序


一、背景

這個學期開設的Java程序設計課程,需要用課堂派來簽到和平常練習,老師苦於課堂派后台的課堂測試需要人工填入題目,好在課堂派運行符合格式的題目直接從word文檔中導入,於是讓我們來寫一個小程序來實現這個格式轉換。老師用的源題庫是有特殊格式的,這樣我們就可以通過一些特殊的標記來實現對源題庫的讀取,我最開始使用C++來實現的,后來補充的Java的版本。該程序主要是對string的操作,二者之中有許多相同的函數方法,但具體的寫法卻有所不同,同時Java的限制數組越界、不能更改String的一些特點,也讓有些頭疼,Java寫的還是太少了!

二、格式要求

源題庫樣例:

目標題庫格式:

 

具體要求:

1.第一行為題干,中間不要換號(課堂派后台只能識別一行題干),可以加題號,也可以不加題號,編寫程序時可以通過一個選項開關讓使用者決定是否需要保留題號。

2.答案要寫在題目開頭或者結尾,用括號括起來,大小寫括號均可。在題干末尾添加本題的類型和分數,用大括號括起來。題目的類型需要通過答案的個數自己判斷,題目的分數需要程序的使用者來輸入。

3.題干之后是選項行,選項中不要空行,一個選項是單獨的一行,選項字母需要英文大寫。

4.每一道題與下一道題目之間需要空三行作為標志。

5.源題庫中的有些題目可能會有解析,這里解析不需要提取處理。

6.源題庫中出現的Chapter和Section的內容可以輸出到控制台,目標文件中不要出現。

 

三、C++源代碼

 

#include<fstream>  //ifstream
#include<iostream>
#include<string>
#include<map>
using namespace std;

struct subject
{
    int id;//題目序號
    int type;//題目類型
    string stem;//題干內容
    map<string,string>options;//選項與答案的map鍵值對
    int num;//選項個數
    string score;//題目分數
    string key;//答案
    string analysis;//有些題目需要解析
};

int main()
{
    string s,temp;
    string path;
    ofstream outf;
    ifstream inf;
    int cnt=0;//記錄題目的個數
    int num1=0;//單選題個數
    int num2=0;//多選題個數
    int flag=0;//默認保留原題號
    char select;//是否保留題號的選項
    string score;
    struct subject sbj[100];
    string::size_type pos(0);
    cout << "請輸入需要轉換的文本文件路徑:(例:C://in.txt)" <<endl;
    cin >> path;
    if(inf)
    {
        cout << "打開文本文件成功!" <<endl;
    }
    else
    {
        cout << "打開文本文件失敗!" <<endl;
    }
    inf.open(path);//打開文本文件I://chapter1.txt
    cout << "請輸入轉換輸出的文本文件路徑:(例:C://out.txt)" <<endl;
    cin >> path;
    outf.open(path);//需要寫入的文本文件

    //目標文本的讀取
    cout << "轉換完成后的題目是否保留原題號?(y/n)" <<endl;
    while(1)
    {
        cin >> select;
        if(select=='y')
        {
            flag=1;
            break;
        }
        else if(select=='n')
        {
            flag=0;
            break;
        }
        else
        {
            cout << "只能輸入y或n,請重新輸入!" <<endl;
        }
    }
    while (getline(inf, s))
    {
        if(s.substr(0,7)=="Chapter")
        {
            cout<<s<<endl;
        }
        else if(s.substr(0,7)=="Section")
        {
            cout<<s<<endl;
        }
        //提取選項信息
        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;//保存題干內容
            }
            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'))//提取選項信息
                {
                    if(s[0]>='a'&&s[0]<='z')//選項是小寫字母,轉為大寫字母
                    {
                        s[0]=s[0]-32;
                    }
                    sbj[cnt].options.insert(pair<string,string>(s.substr(0,1),s.substr(2,s.length()-2)));//保存選項
                    sbj[cnt].num++;
                }
                else if(s.substr(0,1)=="#")//分隔符,下一道題
                {
                    break;
                }
            }
            cout<<""<<cnt<<"道題識別成功!!"<<endl;
            cout<<sbj[cnt].stem<<endl;
            cout<<"答案:"<<sbj[cnt].key<<endl<<endl;
        }
    }
    cout<<"讀取文本文件成功!"<<endl;

    //目標文本的處理
    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<<"檢測到單選題"<<num1<<"道,多選題"<<num2<<""<<endl;
    cout<<"請輸入題目的分數:[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<< '\n';//寫入題干
        map<string,string>::iterator iter;
        for(iter = sbj[i].options.begin(); iter != sbj[i].options.end(); iter++)
        {
            outf<<iter->first<<"."<<iter->second<< '\n';//寫入選項
        }
        outf<< '\n'<< '\n'<< '\n';
    }
    inf.close();
    outf.close();
    cout<<"文本轉換完成!"<<endl;
    return 0;
}

 

四、Java源代碼

import java.io.*;
import java.util.*;
//import java.util.Map;
//import java.util.HashMap;
class subject
{
     int id;//題目序號
     int type;//題目類型
     int num;//選項個數
     String stem;//題干內容
     int score;//題目分數
     String key;//答案
     String analysis;//有些題目需要解析
     Map<String,String>options=new LinkedHashMap<String,String>();//map映射,LinkedHashSet正序輸出
     public subject()//構造函數
     {
         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;//單選題個數
        int num2=0;//多選題個數
        int flag=0;//默認保留原題號
        char select;//是否保留題號的選項
        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("請輸入需要轉換的文本文件路徑:(例:C://in.txt)");
        pathname_in =in.nextLine();
        System.out.println("請輸入轉換輸出的文本文件路徑:(例:C://out.txt)");
        pathname_out =in.nextLine();
        System.out.println("轉換完成后的題目是否保留原題號?(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,請重新輸入!");
            }
        }
        
        try (FileReader reader = new FileReader(pathname_in);
             BufferedReader br = new BufferedReader(reader) // 建立一個對象,它把文件內容轉成計算機能讀懂的語言
        ) {
            String line;
            //網友推薦更加簡潔的寫法
            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;//保存題干內容
                    }
                    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());//答案和解析的內容
                            pos = temp.indexOf(' ');
                            if(pos==-1){//沒有解析說明
                                sbj[cnt].key= temp.toUpperCase();//寫回
                                System.out.println(sbj[cnt].key);
                            }
                            else {
                                sbj[cnt].key=temp.substring(0,pos);//答案選項
                                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);//選項
                            String detail = line.substring(2,line.length());//選項描述
                            sbj[cnt].options.put(opt,detail);
                            sbj[cnt].num++;  
                        }
                        else
                        {
                            continue;
                        }
                    }
                    System.out.println("第"+cnt+"道題識別成功!!");
                    System.out.println(sbj[cnt].stem);
                    System.out.println("答案:"+sbj[cnt].key+"\n");
                }
                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("檢測到單選題"+num1+"道,多選題"+num2+"道");
        System.out.println("請輸入題目的分數:[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); // 相對路徑,如果沒有則要建立一個新的output.txt文件
            writeName.createNewFile(); // 創建新文件,有同名的文件的話直接覆蓋
            try (FileWriter writer = new FileWriter(writeName);
                 BufferedWriter out = new BufferedWriter(writer)
            ) {
                for(int i=1; i<=cnt; i++){//文本寫入
                    out.write(sbj[i].stem+"\r\n"); 
                    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()+"\r\n");
                    }  
                    out.write("\r\n"+"\r\n"+"\r\n"); 
                }
                out.flush(); // 把緩存區內容壓入文件
            }
        } catch (IOException e){
            e.printStackTrace();
        }
        System.out.println("文本轉換完成!");
    }
}

 

 五、遇到的一些問題

 

1.Java中關於HashMap的元素遍歷的順序問題

摘自https://www.cnblogs.com/xdp-gacl/p/3558625.html

在使用如下的方式遍歷HashMap里面的元素時

for (Entry<String, String> entry : hashMap.entrySet()) {
     MessageFormat.format("{0}={1}",entry.getKey(),entry.getValue());
 }

  發現得到的元素不是按照之前加入HashMap的順序輸出的,這個問題我之前倒是沒有注意過,后來上網查了一下原因,發現是:HashMap散列圖、Hashtable散列表是按“有利於隨機查找的散列(hash)的順序”。並非按輸入順序。遍歷時只能全部輸出,而沒有順序。甚至可以rehash()重新散列,來獲得更利於隨機存取的內部順序。
  總之,遍歷HashMap或Hashtable時不要求順序輸出,即與順序無關。

Map<String, String> paramMap = new HashMap<String, String>();

  可以用java.util.LinkedHashMap 就是按加入時的順序遍歷了。

Map<String, String> paramMap = new LinkedHashMap <String, String>();

  類似的還有 java.util.LinkedHashSet

 

2.C++中對字符串中所有指定的子串進行替換的函數

/*
 * string& str              源字符串
 * const string& old_value  被替換子串
 * const string& new_value  替換子串
 */
string& replace_all(string& str,const string& old_value,const string& new_value)//替換函數
{
    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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM