因爲最近寫Word文檔比較多,發現文檔中不少內容有重複。固然經常使用手法就是Ctrl+V、Ctrl+C,開始可能還行。但隨後客戶提出修改要求時就瘋了。shell
Word中爲啥沒有個變量?
我開始只知道Word有域的概念,但在界面上操做時遇到了困難,很難定義。oop
首先有一個域(Field),引發了個人關注測試
它就是Document Automation下的DocVariable。優化
若是能夠定義這個值和修改(name=value),從某種意義上講word也能夠像程序同樣定義變量了。ui
但問題來了,若是想改變這個值必須經過VBA開發來完成。(-_-寫VB吧)spa
首先按Alt+F11呼出VBA控制檯,選擇你Word文檔的ThisDocument,粘貼如下代碼code
'配置文件名默認爲 word文件名-docvar.txt '配置文件格式 key=value,#爲註釋 '解除DovVariable Field,轉換爲普通文字 Sub unlinkDocVarFields() Dim varResponse As Variant varResponse = MsgBox("是否把文檔中的DocumentVariable域替換爲普通文字?", vbYesNo) If varResponse = vbYes Then Dim bTrack As Boolean bTrack = ActiveDocument.TrackRevisions ActiveDocument.TrackRevisions = False '遍歷DocVariable域 Dim fCount As Integer fCount = 0 For Each oFld In ActiveDocument.Fields If oFld.Type = wdFieldDocVariable Then '撤消域鏈接 oFld.Unlink '無效會被替換 Error! No document variable supplied. fCount = fCount + 1 End If Next oFld ActiveDocument.TrackRevisions = bTrack MsgBox "完成對" & fCount & "個DocVar域替換!" End If End Sub '讀取txt文件中的DovVariable配置 Sub loadDocVarsFile() Dim varResponse As Variant varResponse = MsgBox("是否讀取載入DocVar文件中的配置,並更新全部DocVar域?", vbYesNo) If varResponse = vbYes Then Dim bTrack As Boolean bTrack = ActiveDocument.TrackRevisions ActiveDocument.TrackRevisions = False Dim sFileName As String Dim iFileNum As Integer Dim sBuf As String Dim iPos As Integer Dim sName As String Dim sValue As String sFileName = ActiveDocument.FullName & "-docvar.txt" If Len(Dir$(sFileName)) = 0 Then MsgBox "沒有找到" & sFileName Exit Sub End If '讀取文件 iFileNum = FreeFile() Dim vCount As Integer vCount = 0 Open sFileName For Input As iFileNum Do While Not EOF(iFileNum) Line Input #iFileNum, sBuf If InStr(1, Trim(sBuf), "#") <> 1 Then '#開頭的配置認爲是註釋 iPos = InStr(1, sBuf, "=") '拆分等號 If iPos <> 0 Then sName = Trim(Left(sBuf, iPos - 1)) 'key sValue = Trim(Mid(sBuf, iPos + 1, Len(sBuf) - iPos)) 'value If Len(sName) <> 0 Then ActiveDocument.Variables(sName).Value = sValue '更新文檔的Variables vCount = vCount + 1 End If End If End If Loop Close iFileNum '更新所有wdFieldDocVariable域 Dim fCount As Integer fCount = updateAllDocVarField() ActiveDocument.TrackRevisions = bTrack MsgBox "完成讀取載入" & vCount & "個DocVar配置信息,並更新" & fCount & "個域!" End If End Sub '把光標位置所作的域修改的值更新到其它同名域 Sub updateSelectDocVar() If Selection.Fields.Count <> 0 Then Dim varResponse As Variant varResponse = MsgBox("是否把此域的內容更新到其它同名域?", vbYesNo) If varResponse = vbYes Then Dim bTrack As Boolean bTrack = ActiveDocument.TrackRevisions ActiveDocument.TrackRevisions = False Dim ofi As Variant Dim fname As String Dim fvalue As String If Selection.Fields(1).Type = wdFieldDocVariable Then fname = getFieldName(Selection.Fields(1)) fvalue = getFieldValue(Selection.Fields(1)) ActiveDocument.Variables(fname).Value = fvalue '更新所有wdFieldDocVariable域 Dim fCount As Integer fCount = updateAllDocVarField() Else MsgBox "域不是DocVariable類型" End If ActiveDocument.TrackRevisions = bTrack MsgBox "完成其它[" & fname & "=" & fvalue & "]" & fCount & "個域值的更新!" End If Else MsgBox "請選擇須要更新的域!" End If End Sub '把word中的DocVarField內容寫入txt文本 Sub saveDocVarsFile() Dim bTrack As Boolean bTrack = ActiveDocument.TrackRevisions ActiveDocument.TrackRevisions = False Dim sFileName As String Dim sFileNameBackup As String Dim iFileNum As Integer Dim sCode As String Dim sPos As Integer sFileName = ActiveDocument.FullName & "-docvar.txt" '老文件名 sFileNameBackup = ActiveDocument.FullName & "-docvar-" & Format(Now(), "yyyyMMddhhmmss") & ".txt" '備份文件名 '備份原有docvar文件 If Len(Dir$(sFileName)) <> 0 Then Name sFileName As sFileNameBackup End If '域修改值更新回DocumentVariables Dim docKey As String Dim docName As String Dim docValue As String Dim docOldValue As String Dim changeList As Collection Set changeList = New Collection Dim changeListCount As Integer docKey = "DOCVARIABLE" changeListCount = 0 For Each oFld In ActiveDocument.Fields If oFld.Type = wdFieldDocVariable Then '從域code中提取DocVar的名字 If Len(oFld) = 0 Then '刪除無效field oFld.Delete Else docName = getFieldName(oFld) docValue = getFieldValue(oFld) '判斷域中定義的DocVar是否存在Variables中 On Error Resume Next docOldValue = ActiveDocument.Variables(docName).Value If Err.Number = 0 Then '存在 If docValue <> docOldValue Then '文檔中域值與Variables中的值不相同時,說明文檔中有修改 changeList.Add ("# 第" & oFld.Code.Information(wdActiveEndPageNumber) & "頁 第" & oFld.Code.Information(wdFirstCharacterLineNumber) & "行 # " & docName & "=" & docValue) changeListCount = changeListCount + 1 End If Else '不存在,直接寫入 ActiveDocument.Variables(docName) = docValue End If On Error GoTo 0 End If End If Next oFld '寫文件 iFileNum = FreeFile() Dim vCount As Integer vCount = 0 Open sFileName For Output As iFileNum Print #iFileNum, "# 保存時間:"; Format(Now(), "yyyy年MM月dd日 hh:mm:ss") Print #iFileNum, "" For Each oVar In ActiveDocument.Variables Dim outline As String outline = oVar.Name & "=" & oVar.Value Print #iFileNum, outline vCount = vCount + 1 Next oVar Print #iFileNum, "" Print #iFileNum, "# 文檔中的域值變動記錄(值衝突)" Print #iFileNum, "" For Each iChange In changeList Print #iFileNum, iChange Next Close iFileNum ActiveDocument.TrackRevisions = bTrack MsgBox "完成對DocVar配置信息的寫入,供寫入" & vCount & "個DocVar," & changeListCount & "個值衝突域!" Shell "Notepad.exe " & sFileName, vbNormalFocus End Sub '更新所有wdFieldDocVariable域,無變化不更新 Private Function updateAllDocVarField() As Integer Dim fCount As Integer fCount = 0 For Each oFld In ActiveDocument.Fields If oFld.Type = wdFieldDocVariable Then If ActiveDocument.Variables(getFieldName(oFld)).Value <> getFieldValue(oFld) Then oFld.Update fCount = fCount + 1 End If End If Next oFld updateAllDocVarField = fCount End Function '獲取DovVariable Field的name Private Function getFieldName(oFld As Variant) As String Dim docKey As String docKey = "DOCVARIABLE" getFieldName = Trim(Mid(oFld.Code, (InStr(1, oFld.Code, docKey) + Len(docKey) + 1), InStr(1, oFld.Code, "\*") - InStr(1, oFld.Code, docKey) - Len(docKey) - 1)) End Function '獲取DovVariable Field的Result(顯示結果) Private Function getFieldValue(oFld As Variant) As String getFieldValue = Trim(oFld.Result) End Function
saveDocVarsFile是來保存你在文檔中定義的DocVariable(爲啥保存,爲了之後批量程序修改)。
loadDocVarsFile是來讀取配置,並更新全部DocVariable域(修改完txt配置後,你就能夠批量替換文檔內容)。orm
unlinkDocVarFields是用來轉換DocVariable域爲普通文本用的(最後的交付,注意必定是最後,不但願採用DocVariable域方式。手工方式是選中Word聽DocVariable區域按Ctrl+Alt+F9)開發
updateSelectDocVar是用來把選擇域中修改的內容當即更新其它同名域的方法文檔
運行saveDocVarsFile就會自動打開一個xxx-docvar.txt的文件(#爲註釋)
加入如下內容並保存txt(格式:name=value)
測試=測試文字段落
運行loadDocVarsFile
Insert->Quick Parts->Field->DocVariable,name輸入剛纔寫的'測試'
這時你會發現,內容顯示爲「測試文字段落」。(注意b,c順序,若是先作c可能顯示空白,由於尚未值)
複製提供多個位置使用
在一個Word文字中加入abc。再執行saveDocVarsFile。文本的內容會變爲
# 保存時間:2012年09月20日 13:19:42 測試=測試文字段落 # 文檔中的域值變動記錄(值衝突) # 第1頁 第2行 # 測試=測試文字abc段落
saveDocVarsFile會自動發現變化的域所在的頁號與行號。
把 測試=測試文字段落 替換爲 測試=測試文字abc段落,保存(意思是你接受了這個值對全局的修改)
# 保存時間:2012年09月20日 13:19:42 測試=測試文字abc段落 # 文檔中的域值變動記錄(值衝突) # 第1頁 第2行 # 測試=測試文字abc段落
再執行loadDocVarsFile
文檔中的DocVariable('測試')顯示的位置都會改變。
DocVariable域能夠支持複製到其它文檔。若是再用這個宏時注意要先save再load。若是直接load將致使內容丟失。
程序對我來講屬於夠用範圍,固然還有能夠優化的地方你們能夠本身再改改。(如:能夠寫一個加入DocVariable的宏,就能夠不用先load)
個人環境是XP,Word 2010,其它環境沒有試驗過。