這個不能算瞎折騰,也算是被逼的沒辦法了。從接手webgame開始,看到那麼多的excel文件被翻譯爲繁體,我的頭就沒小過。現在因爲新版本的問題又得重新翻譯一次,經歷過上一次慘痛的過程,這一次變懶了。
大陸內地使用的是簡體中文,臺灣地區使用的是繁體中文,我們將遊戲中用到的配置和所有需要漢化的文字提供給臺灣合作伙伴,他們翻譯後再回傳給我們。實際上面對那麼大的工程,是不可能所有內容都一個一個去看的,所以採用的是word或是excel自動的簡轉繁功能,但這樣的方式帶來了比較致命的問題,合作方往往在你重新生成配置文件後,測試過程中發現一些文字需要重新替換,出現這種情況的原因主要是在於臺灣地區的方言和大陸所使用的描述不一樣。比如“充值” –> “儲值”、“信息”-> “訊息”、“設置”->“設定”等等,很多…,還有就是一段任務的描述,對方在測試時也覺得要進行修改、調整,這個時候也得重新生成,然後打包、上傳、更新版本號…
之前因爲這個,曾經用.net寫過一個查找指定文件夾下所有文件(包含excel)的小應用程序,檢測後生成一個html,裏面重點標識出匹配到輸入文字的文件(支持點擊打開該文件)。現在是先讓對方提供一個轉換庫,比如上面說的,然後寫程序將所有需要檢測的文件進行替換(重點是excel),因爲遊戲中需要用到的excel文件異常多,近200個左右。數量倒不是很大,但重點是一個excel中的某一個sheet可能就超過1萬行的數據了。
最初想法是覺得很簡單,只是替換而已,就想用php去做這件事,可到後來發現php使用phpexcel這個庫對excel讀取的時候,遇到中文,特別是繁體中文時問題多多,基本上不能讀取完一個文件夾下的excel文件,自行中斷了。然後想想說用vbs寫個程序吧,畢竟有近200個文件呢,不太想寫個宏,然後把一百多個文件打開都來執行一個這個宏命令。
寫的時候遇到了一些問題,比如在切換寫javascript、vbscript和actionscript的時候容易犯小錯誤,二就是對vbscript操作dom不熟悉,三就是需要找到可以讓循環在跑的過程中能sleep,因爲文件過多,循環無法避免而且是很漫長的過程,必須要用到sleep。寫是寫完了,不過整個跑的效果並不理想:太慢…
假設平均一個excel文件爲 15列 * 10000行,如今有超過185個這樣的excel文件,那麼大約有 27,750,000(近三千萬次循環),不包含讀取文件,以及循環再去替換它的內容然後寫入內容的操作。下一步是要優化這個工具,因爲以後它會被經常用到,先放一下工具大致實現(使用的是hta,可以本地直接運行)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Excel VBA正則表達式替換</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <hta:application id="appGTJExcel" applicationname="appGTJExcel" singleinstance="yes" border="thin" scroll="no" maximizeButton="no"> <style type="text/css"> <style type="text/css"> *{margin:0; padding:0;} body {font-size:14px; background-color:#eee; width:100%; height:100%; overflow:hidden;} .exec-btn {display:block; border:1px solid #666; background-color:#9c0; color:#360; padding:5px 5px 3px 5px; width:70px; height:30px; vertical-align:middle; cursor:pointer;} fieldset {height:440px; width:1050px; margin-top:20px; display:block;} legend {margin-left:20px; display:none;} #container {height:100%; overflow:auto; list-style-type: none;} #container li {height:20px; line-height:20px; overflow:hidden; vertical-align:middle; margin:10px 10px 10px 0;} .red {color:#ff0000;} </style> </head> <body> <button class="exec-btn" onclick="replaceHandler()">開始替換</button> <fieldset> <legend>VBS替換內容</legend> <ul id="container"> <li>點擊開始執行替換操作</li> </ul> </fieldset> <script language="javascript"> 1: 2: function getEl(id) { 3: return typeof id === 'string' ? document.getElementById(id) : id; 4: } 5: 6: function addMessage(msg) { 7: var li = document.createElement("li"); 8: li.innerHTML = msg; 9: 10: getEl("container").appendChild(li); 11: } 12: 13: function replaceStr(str) { 14: var arr = [], 15: newArr = []; 16: 17: arr = [ 18: '將要被替換的文字' 19: ]; 20: 21: newArr = [ 22: '被替換後的文字,與arr數組對應的元素一對一' 23: ]; 24: 25: for (var i = 0, len = arr.length; i < len; ++i) { 26: str = str.replace(new RegExp(arr[i], "g"), newArr[i]); 27: } 28: 29: return str; 30: }</script> 1: 2: 3: <script language="vbscript"> 4: '函數 返回類型 expression 參數範圍 5: 'CBool Boolean 任何有效的字符串或數值表達式。 6: 'CByte Byte 0 至 255。 7: 'CCur Currency -922,337,203,685,477.5808 至922,337,203,685,477.5807。 8: 'CDate Date 任何有效的日期表達式。 9: 'CDbl Double 負數從 -1.79769313486232E308 至 -4.94065645841247E-324;正數從 4.94065645841247E-324 至 1.79769313486232E308。 10: 'CDec Decimal 零變比數值,即無小數位數值,爲 11: '+/-79,228,162,514,264,337,593,543,950,335。對於 28 位小數的數值,範圍則爲 12: '+/-7.9228162514264337593543950335;最小的可能非零值是 0.0000000000000000000000000001。 13: 'CInt Integer -32,768 至 32,767,小數部分四捨五入。 14: 'CLng Long -2,147,483,648 至 2,147,483,647,小數部分四捨五入。 15: 'CSng Single 負數爲 -3.402823E38 至 -1.401298E-45;正數爲 1.401298E-45 至 3.402823E38。 16: 'CStr String 依據 expression 參數返回 Cstr。 17: 18: Option Explicit 19: 'On Error Resume Next 20: 21: Dim folderPath, folder 22: Dim fso, file, files 23: Dim fileNums 24: Dim FileString() 25: Dim re 26: Dim i 27: 28: folderPath = "D:\excel\...." 29: i = 0 30: 31: Set fso = CreateObject("Scripting.FileSystemObject") 32: 33: 34: '執行替換操作 35: Sub replaceHandler() 36: 37: If fso.FolderExists(folderPath) Then 38: Set folder = fso.GetFolder(folderPath) 39: Set files = folder.Files 40: fileNums = files.Count 41: 42: Call addMessage("目錄“"+folderPath+"”下的總文件數:<strong class='red'>" + CStr(fileNums) + "</strong>個") 43: 44: Set re = new RegExp 45: re.Pattern = ".xlsx$" 46: re.Global = True 47: re.ignoreCase = false 48: 49: For Each file In files 50: If re.test(file.name) Then 51: i=i+1 52: Call addMessage(CStr(i) + "--" + file.name) 53: replaceExcel(folderPath + "\" + file.name) 54: End If 55: Sleep(3*1000) 56: 57: 'Exit For 58: 59: Next 60: 61: MsgBox "所有文件已處理完成", 64, "溫馨提示" 62: Else 63: Msgbox "指定的目錄“" + folderPath + "”不是一個文件夾" 64: End If 65: 66: End Sub 67: 68: 69: 70: 71: Sub replaceExcel(filePath) 72: Dim objExcel 73: Dim excelBook 74: Dim objSheet 75: 76: Set objExcel = CreateObject("Excel.Application") 77: Set excelBook = objExcel.Workbooks.Open(filePath) 78: Set objSheet = excelBook.Worksheets(1) 79: 80: '不彈出是否保存excel或是取消操作 81: objExcel.DisplayAlerts = False 82: 83: Dim cols 84: Dim rows 85: 86: cols = objSheet.UsedRange.Cells.Columns.Count 87: rows = objSheet.UsedRange.Cells.Rows.Count 88: 89: addMessage("文件<a href='"+filePath+"'>"+filePath+"</a> 活動區有:<strong class='red'>" & cols & "</strong>列 <strong class='red'>" & rows & "</strong>行") 90: 91: Dim i,j,s 92: 93: i = 1 94: j = 1 95: Do While i <= rows 96: j = 1 97: Do While j <= cols 98: s = objSheet.Cells(i, j).Value 99: s = CStr(s) 100: 101: If Len(s) > 1 Then 102: objSheet.Cells(i, j).Value = replaceStr(s) 103: 104: 'Call addMessage((i+1) & "行" & (j+1) & "列:" + s + "---" + replaceStr(s)) 105: End If 106: j = j + 1 107: Loop 108: Sleep(100) 109: i = i + 1 110: Loop 111: 112: 'Close workbook and quit Excel. 113: 'excelBook.SaveAs "d:\test.xls" '保存工作表 114: 'excelBook.Close 115: 116: objExcel.ActiveWorkbook.Save 117: objExcel.ActiveWorkbook.Close 118: objExcel.Application.Quit 119: 120: Set objExcel = Nothing 121: Set excelBook = Nothing 122: Set objSheet = Nothing 123: 124: End sub 125: 126: 127: Sub Sleep(MSecs) 128: Dim fso 129: Dim objOutputFile 130: 131: Set fso = CreateObject("Scripting.FileSystemObject") 132: If Fso.FileExists("sleeper.vbs")=False Then 133: Set objOutputFile = fso.CreateTextFile("sleeper.vbs", True) 134: objOutputFile.Write "wscript.sleep WScript.Arguments(0)" 135: objOutputFile.Close 136: End If 137: CreateObject("WScript.Shell").Run "sleeper.vbs " & MSecs,1 , True 138: End Sub 139: 140: '"Automation服務器不能創建對象" 的多種解決辦法 141: 'http://www.cnblogs.com/BTQ/archive/2008/05/29/1209738.html</script> </body> </html>
運行起來的效果圖大致如下圖所示: