Golang正則筆記 :使用正規表示式處理題庫文字

Yl00G發表於2018-06-07

前言

由於企業內部的一些考試需要,有些同事要時常通過一個word格式的題庫檔案來查詢相應題目,但在手機上用word進行查詢,總覺得操作上很不方便。藉著這個契機,應用Golang和Kotlin開發了一個小工具,方便同事可快捷的查詢題目。

也是希望把開發過程中的知識點記錄下來,方便以後複習,因為不知道什麼時候就會又一次忘了怎麼寫正則了。

雖然上面說了那麼多,其實就是想幫同事作弊 ლ(╹◡╹ლ)

題庫檔案參考

以下是我的題庫檔案,可參考: tiku.txt


單選題: (共912小題,總分:1分)

1 . ( )是銀行網點直接和顧客接觸的員工,因此在客戶建立對銀行網點第一印象、維持良好的銀行網點服務形象方面起著重要作用 (1.50分)
A  網點負責人
B  大堂經理
C  櫃員
D  客戶經理
標準答案 :C
試題解析 :
1,065 . 櫃員櫃面營銷與櫃面服務包括 (2分)
A  負責業務辦理間隙識別優質客戶的工作,並將客戶引導到最合適的服務渠道
B  保持頭、臉、手、著裝、修整、飾物的清潔、規範,保持職業化服務形象
C  執行站姿挺拔、坐姿端莊、行姿規範、行為檢點、微笑親和、致意得體、道歉真誠的服務要求,保持良好服務行為
D  執行聲音親和、語句清晰、措辭客氣、表達明瞭、稱呼準確、問候得體、適當寒暄的服務語言規範
E  負責詳細記錄客戶資訊,聆聽、發現客戶真實需求,為下一步客戶經理的關係維護打下基礎
標準答案 :A B C D E
試題解析 :
1,480 . 根據我社其它物品管理的規定,對於印章和鑰匙,對應的調撥機構為上級管理機構,而假幣上繳的對應上級機構為現金管理(分)中心。 (1分)
正確
錯誤
標準答案 :正確

複製程式碼

需求就是將這個檔案,儲存為sqlite資料庫檔案,並嵌到Android App裡。

第一步,使用正規表示式解析檔案,並拆分出題幹,選項,答案几個元素,再分別存入資料庫裡。

正則我用Golang實現,資料庫用sqlite ,因為最後這個資料庫是要給Android用的。

一: 先分析題幹部分:

1 . ( )是銀行網點直接和顧客接觸的員工,因此在客戶建立對銀行網點第一印象、維持良好的銀行網點服務形象方面起著重要作用 (1.50分)

可分為三個部分來解析

  1. 題序:[ 1 . ]

正則表達:

完整的正則: ^\s*?(?P<index>\d+,*?\d*?\s*?\.)\s*?

^\s*? 表示以0或1個以上的空格開頭 ,^表示匹配開頭

(?P<index>) 是golang的分組語法,在這裡不用理會

\d+,*?\d*?\s*?\.
\d+ : 表示1個以上的數字
,*? :  0或1個逗號 , 因文字里的題序格式類似這樣: 1,234 ,這個正則不支援 1,234,567 ,因為我覺得不太可能需要那麼大的數
\d*? : 表示0個以上的數字
\s*?\. : 若干空格並以 . 結束
複製程式碼

Golang 實現:

func findSubject(line string) (result bool, s string) {
	reg := regexp.MustCompile(`^\s*?(?P<index>\d+,*?\d*?\s*?\.)\s*?(?P<subject>.*)(?P<score>\s*?(.*分))$`)
	matches := reg.FindStringSubmatch(line)
	if len(matches) > 0 {
		return true, matches[2]
	}
	return false, ""
}
複製程式碼
  1. 題幹正文 : [( )是銀行網點直接和顧客接觸的員工,因此在客戶建立對銀行網點第一印象、維持良好的銀行網點服務形象方面起著重要作用 ]
分析題幹需要同時配合結尾來進行解析,可以明顯的看到,每道題都以(1.50分)這樣的格式結尾

(?P<subject>.*)(?P<score>\s*?(.*分))$
複製程式碼

二: 分析選項:

	^\s?(?P<index>[A-Z]\s?)\s?(?P<content>.*)
	選項總是以字母開頭,所以用 [A-Z] 匹配即可。
複製程式碼

Golang 實現:

func findOptions(line string) (result bool, s string) {
	//判斷選擇題
	reg := regexp.MustCompile(`^\s?(?P<index>[A-Z]\s?)\s?(?P<content>.*)`)
	matches := reg.FindStringSubmatch(line)
	if len(matches) > 0 {
		return true, line
	}

	reg = regexp.MustCompile(`^(正確)|^(錯誤)`) //這裡需要注意,判斷題並不是以[A-Z]開頭的。
	matches = reg.FindStringSubmatch(line)

	if len(matches) > 0 {
		return true, matches[0]
	}

	return false, ""
}
複製程式碼

分析答案就太簡單了:

func findAnswer(line string) (result bool, s string) {
	matched, _ := regexp.MatchString(`^(標準答案 :)`, line)
	if matched {
		return true, line
	}
	return false, ""
}
複製程式碼

不多說了,最後就是儲存進sqlite了

func saveToDB() {
	db, err := sql.Open("sqlite3", "./yee.db")
	checkErr(err)

	for _, q := range questionList {
		stmt, err := db.Prepare(`INSERT INTO question(subject, options, answer) values(?,?,?)`)
		checkErr(err)

		res, err := stmt.Exec(q.Subject, strings.Join(q.Options, "||"), q.Answer) //選項之間用 || 分隔即可,簡單處理
		checkErr(err)
		id, err := res.LastInsertId()

		checkErr(err)

		fmt.Println(id)
	}
}

複製程式碼

image

完整程式碼請參考Gayhub: https://github.com/yeelone/bankolin-demo

第二步,實現Android App

將第一步生成的 yee.db 資料庫檔案放進新建的Android專案裡,目錄為 src/main/res/raw ,

接著我們需要在APP啟動時,將yee.db檔案拷進android的資料檔案地址

先實現一個Helper類併為context進行擴充套件:

package com.example.elone.myapplication

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import org.jetbrains.anko.db.ManagedSQLiteOpenHelper

class DatabaseHelper(ctx: Context) : ManagedSQLiteOpenHelper(ctx, "yee.db", null, 1) {
    companion object {
        private var instance: DatabaseHelper? = null

        @Synchronized
        fun Instance(context: Context): DatabaseHelper {
            if (instance == null) {
                instance = DatabaseHelper(context.applicationContext)
            }
            return instance!!
        }
    }

    override fun onCreate(database: SQLiteDatabase) {
    }

    override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
    }
}

val Context.database: DatabaseHelper
    get() = DatabaseHelper.Instance(applicationContext)
複製程式碼

再接著回到MainActivity

private fun importDatabase() {
        // 存放資料庫的目錄
        var dirPath = "/data/data/"+PACKAGE_NAME+"/databases"
        var dir = File(dirPath)
        if (!dir.exists()) {
            dir.mkdir()
        }
        // 資料庫檔案
        var file = File(dir, "yee.db")
        try {
            if (!file.exists()) {
                file.createNewFile()
            }
            // 載入需要匯入的資料庫
            var instream: InputStream = this.applicationContext.resources.openRawResource(R.raw.yee)
            var fos = FileOutputStream(file)
            var buffer  = ByteArray(instream.available())
            instream.read(buffer)
            fos.write(buffer)
            instream.close()
            fos.close()
        } catch ( e: FileNotFoundException) {
            e.printStackTrace()
        }
    }
複製程式碼

這是第一次用到kotlin Anko sqlite,記錄一下查詢語法:

    private fun searchQuestion() {
        val editText = findViewById<EditText>(R.id.searchText)
        val rows = database.use {
            select("question")
                    .whereSimple("(subject like '%"+editText.text+"%') ")
                    .exec {
                        parseList(classParser<Question>())
                    }
        }

        mListView.adapter = MainAdapter(rows)
    }
複製程式碼

最終成果如圖:

image

歡迎訪問原文地址: Github Page

相關文章