Gox語言實現(xiàn)的自動判斷GB2312/GBK/GB18030編碼文件并轉(zhuǎn)換為UTF-8文件的工具-GX34

本例中代碼已經(jīng)有詳細注釋故痊,主要體現(xiàn)了Gox語言編碼檢測豫缨、二進制字節(jié)(byte)數(shù)據(jù)類型的處理、使用選擇文件對話框和信息確認對話框摔桦、使用LCL庫編寫GUI圖形界面等知識社付。本例也可以舉一反三用于檢測和轉(zhuǎn)換其他文件編碼。

下面是運行該程序的效果截圖邻耕,可以在文本框中粘貼入所需檢測的文本鸥咖,也可以點下面的“打開文件”按鈕來選擇所需檢測的文件,然后程序會自動檢測該文件的編碼兄世,如果是GB18030的編碼啼辣,會提示用戶確認是否要進行編碼轉(zhuǎn)換,用戶確認后會進行從GB18030至UTF-8的編碼轉(zhuǎn)換碘饼。

運行效果截圖
// quickCheck函數(shù)用于根據(jù)文件頭快速判斷文件的類型
// 輸入?yún)?shù)是一個字節(jié)數(shù)組
// 注意無論是GB18030還是UTF-8編碼的文件熙兔,均可以沒有對應(yīng)的文件頭,
// 因此判斷文件頭并不總能判斷出文件類型
// 但一般來說存在對應(yīng)文件頭艾恼,就可以確定是該編碼的文件
quickCheck = fn(bytesA) {
    lenT = len(bytesA)

    if lenT < 3 {
        return ""
    }

    // 判斷一開始是否是UTF-8的BOM頭住涉,如果是的話,直接可斷定是
    if bytesA[0] == 0xef && bytesA[1] == 0xbb && bytesA[2] == 0xbf {
        return "UTF8-BOM"
    }

    if lenT < 4 {
        return ""
    }

    // 判斷是否是GB18030文件的文件頭
    if bytesA[0] == 0x84 && bytesA[1] == 0x31 && bytesA[2] == 0x95 && bytesA[3] == 0x33 {
        return "GB18030"
    }

    return ""
}

// 詳細檢查是否是UTF-8編碼的文件
// 方法是注意檢查每個字符钠绍,看是否存在UTF-8編碼規(guī)則之外的字符
// 如果全是規(guī)則之內(nèi)的字符舆声,則可以判定是UTF-8編碼
checkUTF8 = fn(bytesA) {
    utf8ByteT = 0

    for i, v = range bytesA {
        c = int(v)

        if utf8ByteT == 0 {
            if c >= 0x00 && c <= 0x7F {
                continue
            }

            if c >= 0xC0 && c <= 0xDF {
                utf8ByteT = 1
                continue
            }

            if c >= 0xE0 && c <= 0xEF {
                utf8ByteT = 2
                continue
            }

            if c >= 0xF0 && c <= 0xF7 {
                utf8ByteT = 3
                continue
            }

        } else {
            if c >= 0x80 && c <= 0xBF {
                utf8ByteT -= 1
                continue
            }
        }

        return false
    }

    return true
}

// 詳細檢查是否是GB18030編碼的文件
// 方法是注意檢查每個字符,看是否存在GB18030編碼規(guī)則之外的字符
// 如果全是規(guī)則之內(nèi)的字符柳爽,則可以判定是GB18030編碼
checkGB18030 = fn(bytesA) {
    gbByteT = 0

    for i, v = range bytesA {
        c = int(v)

        if gbByteT == 0 {
            if c >= 0x00 && c <= 0x7F {
                continue
            }
            if c >= 0x81 && c <= 0xFE {
                gbByteT = 1
                continue
            }

        } elif gbByteT == 1 {
            if (c >= 0x40 && c <= 0x7E) || (c >= 0x80 && c <= 0xFE) {
                gbByteT = 0
                continue
            }
            if c >= 0x30 && c <= 0x39 {
                gbByteT = 2
                continue
            }

        } elif gbByteT == 2 {
            if c >= 0x81 && c <= 0xFE {
                gbByteT = 3
                continue
            }

        } else {
            if c >= 0x30 && c <= 0x39 {
                gbByteT = 0
                continue
            }
        }

        return false
    }

    return true
}

// 詳細檢查文件編碼的入口函數(shù)
// 可以調(diào)節(jié)其中的判斷順序來選擇優(yōu)先判斷何種編碼
// 本例中優(yōu)先先判定是否是UTF-8編碼
// 如果沒有任何字符不屬于UTF8編碼的規(guī)則媳握,則認定為UTF-8編碼
// 接下來才判斷GB18030
// 如果都不符合,則返回空字符串
detailCheck = fn(bytesA) {

    if checkUTF8(bytesA) {
        return "UTF-8"
    }

    if checkGB18030(bytesA) {
        return "GB18030"
    }


    return ""
}


// 檢查編碼的入口函數(shù)
// 先用快速檢測方法(檢測文件頭)來試圖檢測文件編碼
// 快速法無法檢測出的情況下磷脯,才進行詳細檢測
checkText = fn(bytesA) {
    rs = quickCheck(bytesA)
    
    if rs == "" {
        rs = detailCheck(bytesA)
    }

    return rs
}

// 下面才是主程序部分的開始

// 初始化LCL圖形界面庫
errT = lcl.InitLCL()

if errT != nil {
    plerr(errT)
    exit()
}

// 創(chuàng)建LCL圖形界面應(yīng)用并初始化
application = lcl.GetApplication()
application.Initialize()

// 設(shè)置應(yīng)用標題
application.SetTitle("編碼檢測與轉(zhuǎn)換")
application.SetMainFormOnTaskBar(true)

// 創(chuàng)建主窗口并設(shè)置寬高蛾找、標題、位置等
mainForm = application.CreateForm()

mainForm.SetWidth(620)
mainForm.SetHeight(480)
mainForm.SetCaption("編碼檢測與轉(zhuǎn)換")
mainForm.SetPosition(lcl.PoScreenCenter)

mainForm.Font().SetSize(11)

// 創(chuàng)建一個多行文本框赵誓,用于放轉(zhuǎn)換后的文本
memo1 = lcl.NewMemo(mainForm)
memo1.SetParent(mainForm)
memo1.SetBounds(10, 20, 600, 400)
memo1.Font().SetSize(11)
memo1.SetAnchors(lcl.NewSet(lcl.AkTop, lcl.AkBottom, lcl.AkLeft, lcl.AkRight))
memo1.SetScrollBars(lcl.SsAutoVertical)
memo1.SetWordWrap(true)


// 設(shè)置按“打開文件”按鈕后的回調(diào)函數(shù)
onButtonOpenClick = fn(sender) {
    // 打開圖形化的文件選擇框讓用戶選擇文件
    fileNameT = gui.SelectFile("選擇文件……", "所有類型", "*")
    
    if tk.IsErrorString(fileNameT) {
        gui.SimpleError("錯誤提示", tk.GetErrorString(fileNameT))
        return
    }

    // 以二進制方式載入文件中的所有字節(jié)
    bytesT, errT = tk.LoadBytesFromFileE(fileNameT, -1)
    
    if errT != nil {
        gui.SimpleError("錯誤提示", errT.Error())
        return
    }

    // 檢測文本編碼
    rs = checkText(bytesT)

    if rs == "" {
        gui.SimpleError("錯誤提示", "無法推測編碼")
        return
    }

    outStrT = ""

    // 如果是GB18030編碼打毛,則提示用戶確認是否轉(zhuǎn)換為UTF-8編碼;否則直接顯示該文件
    if rs == "GB18030" {
        confirmT = gui.GetConfirm("請選擇", "文件編碼是"+rs+"俩功,是否轉(zhuǎn)換為UTF-8幻枉?")

        if confirmT {
            outStrT = tk.ConvertToUTF8(bytesT, "GB18030")
        } else {
            outStrT = string(bytesT)
        }
    } elif rs == "UTF8-BOM" {
        confirmT = gui.GetConfirm("請選擇", "文件編碼是"+rs+",是否去除BOM頭诡蜓?")

        if confirmT {
            outStrT = string(bytesT[3:])
        } else {
            outStrT = string(bytesT)
        }
    } else {
        outStrT = string(bytesT)
    }

    memo1.SetText(outStrT)
}

// 點按“另存為”按鈕的回調(diào)函數(shù)
onButtonSaveAsClick = fn(sender) {
    // 提示用戶確認
    confirmT = gui.GetConfirm("請選擇", "如果文件沒有轉(zhuǎn)換為UTF-8熬甫,保存時可能會造成字符錯亂并無法恢復(fù),是否要繼續(xù)蔓罚?")

    if !confirmT {
        return
    }

    // 彈出另存文件的對話框讓用戶選擇另存為的文件路徑和文件名
    fileNameT = gui.SelectSaveFile("選擇文件……", "所有類型", "*")
    
    if tk.IsErrorString(fileNameT) {
        gui.SimpleError("錯誤提示", tk.GetErrorString(fileNameT))
        return
    }

    textT = memo1.Text()

    rs = tk.SaveStringToFile(textT, fileNameT)

    if tk.IsErrorString(rs) {
        gui.SimpleError("錯誤提示", tk.GetErrorString(rs))
        return
    }

    // 提示已經(jīng)保存成功
    gui.SimpleInfo("信息提示", "文件已保存至:" + fileNameT)
}

// 點按“關(guān)閉”的回到函數(shù)椿肩,結(jié)束圖形界面程序的運行
onButtonCloseClick = fn(sender) {
    application.Terminate()
}

// 在主窗口增加“打開文件”的按鈕
buttonOpen = lcl.NewButton(mainForm)
buttonOpen.SetParent(mainForm)
buttonOpen.SetLeft(10)
buttonOpen.SetTop(435)
buttonOpen.SetCaption("打開文件")
buttonOpen.SetAnchors(lcl.NewSet(lcl.AkBottom, lcl.AkLeft))
buttonOpen.SetOnClick(lcl.NewTNotifyEvent(onButtonOpenClick))

// 在主窗口增加“另存”的按鈕
buttonSaveAs = lcl.NewButton(mainForm)
buttonSaveAs.SetParent(mainForm)
buttonSaveAs.SetLeft(110)
buttonSaveAs.SetTop(435)
buttonSaveAs.SetCaption("另存")
buttonSaveAs.SetAnchors(lcl.NewSet(lcl.AkBottom, lcl.AkLeft))
buttonSaveAs.SetOnClick(lcl.NewTNotifyEvent(onButtonSaveAsClick))

// 在主窗口增加“關(guān)閉”的按鈕
buttonClose = lcl.NewButton(mainForm)
buttonClose.SetParent(mainForm)
buttonClose.SetLeft(210)
buttonClose.SetTop(435)
buttonClose.SetCaption("關(guān)閉")
buttonClose.SetAnchors(lcl.NewSet(lcl.AkBottom, lcl.AkLeft))
buttonClose.SetOnClick(lcl.NewTNotifyEvent(onButtonCloseClick))

// 啟動圖形界面運行
application.Run()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脚粟,隨后出現(xiàn)的幾起案子覆旱,更是在濱河造成了極大的恐慌,老刑警劉巖核无,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扣唱,死亡現(xiàn)場離奇詭異,居然都是意外死亡团南,警方通過查閱死者的電腦和手機噪沙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吐根,“玉大人正歼,你說我怎么就攤上這事】介伲” “怎么了局义?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵喜爷,是天一觀的道長。 經(jīng)常有香客問我萄唇,道長檩帐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任另萤,我火速辦了婚禮湃密,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘四敞。我一直安慰自己泛源,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布忿危。 她就那樣靜靜地躺著达箍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铺厨。 梳的紋絲不亂的頭發(fā)上幻梯,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音努释,去河邊找鬼碘梢。 笑死,一個胖子當著我的面吹牛伐蒂,可吹牛的內(nèi)容都是我干的煞躬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逸邦,長吁一口氣:“原來是場噩夢啊……” “哼恩沛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缕减,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤雷客,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后桥狡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搅裙,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年裹芝,在試婚紗的時候發(fā)現(xiàn)自己被綠了部逮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡嫂易,死狀恐怖兄朋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怜械,我是刑警寧澤颅和,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布傅事,位于F島的核電站,受9級特大地震影響峡扩,放射性物質(zhì)發(fā)生泄漏享完。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一有额、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彼绷,春花似錦巍佑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至猜旬,卻和暖如春脆栋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洒擦。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工椿争, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人熟嫩。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓秦踪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掸茅。 傳聞我的和親對象是個殘疾皇子椅邓,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355