VBA 收集 Word關鍵字批量處理-Excel版
- UserForm1(窗體代碼)
- 業務邏輯
- 工具模塊
- 性能優化
- Sheet1(關鍵字)(工作表按鈕事件)
- ThisWorkbook(工作簿事件)
- 引用 word
- 源文件
- 參考資料
預覽圖-內涵圖
copy /b 圖片.gif /b + 壓縮包.zip /b 結果圖片.gif
- 20220321
1 修復遍歷多級目錄時生成文件放錯位置的BUG。
2 優化開始按鈕,改為切換開始暫停(其實就是結束,再次開始,可以繼續處理,只有實時日志會清空重新開始打印)。
3 優化性能,沒2000個文檔,重啟一次Word。(切記要隱藏運行,如果顯示界面,未和諧的授權窗口會卡住需要手點跳過)雖然這么做個,但是暫時還不知道變慢的原因,內存CPU都顯示正常。
UserForm1(窗體代碼)
窗體邏輯主要是:
窗體內容初始化。控件事件處理。
Private Sub UserForm_Initialize
()Dim currPath$
, currName$currPath
= ThisWorkbook.path
& "\"currName
= Left(ThisWorkbook.
Name, InStrRev
(ThisWorkbook.
Name, ".") - 1)源文件的目錄TextBox.
Text = currPath
& SOURCE_FILE_PATH完成文件的目錄TextBox.
Text = currPath
& FINISHED_FILE_PATH失敗文件的目錄TextBox.
Text = currPath
& ERROR_FILE_PATH跳過文件的目錄TextBox.
Text = currPath
& SKIP_FILE_PATH成功日志TextBox.
Text = currPath
& currName
& SUCCESS_FILE_SUFFIX失敗日志TextBox.
Text = currPath
& currName
& ERROR_FILE_SUFFIX跳過日志TextBox.
Text = currPath
& currName
& SKIP_FILE_SUFFIXsuccessLogFile
= 成功日志TextBox.
TexterrLogFile
= 失敗日志TextBox.
TextskipLogFile
= 跳過日志TextBox.
TextSet myConsole
= 日志窗口TextBoxshowDoc
= 處理時顯示文檔CheckBox.Value
With Me.WebBrowser1.Navigate
"about:blank".Document.
Write "<body scroll='no' style='margin: 0;border = 0;'><img id='img' src='https://img-blog.csdnimg.cn/00f4705c12f34cdc99636aedf2fe1f1e.gif' style='width: 100%;height:100%;'></body>"End With子目錄深度ScrollBar.
Min = 0日志窗口TextBox.
Text = "日志窗口:" & vbCrLf
& vbCrLf
& " 笑 蝦" & vbCrLf
& "天上游龍水中蛟,不羨高飛入云霄。" & vbCrLf
& "生來無事終天笑,未曾到老先彎腰。" & vbCrLf
& vbCrLf
End SubPrivate Sub UserForm_Activate
()
子目錄深度ScrollBar.Value
= 0
End SubPrivate Sub 獲取源文件目錄Button_Click
()Dim path$
, arr
() As String源文件的目錄TextBox.
Text = 選擇目錄
()Call 刷新目錄結構
(源文件的目錄TextBox.
Text, 子目錄深度ScrollBar.Value
)
End SubPrivate Sub 成功日志TextBox_Change
()successLogFile
= 成功日志TextBox.
Text
End SubPrivate Sub 失敗日志TextBox_Change
()errLogFile
= 失敗日志TextBox.
Text
End SubPrivate Sub 跳過日志TextBox_Change
()skipLogFile
= 跳過日志TextBox.
Text
End SubPrivate Sub 子目錄深度ScrollBar_Change
()子目錄深度TextBox.Value
= 子目錄深度ScrollBar.Value
Call 刷新目錄結構
(源文件的目錄TextBox.
Text, 子目錄深度ScrollBar.Value
)
End SubPrivate Sub 處理時顯示文檔CheckBox_Change
()
On Error Resume NextshowDoc
= 處理時顯示文檔CheckBox.ValuewordApp.Visible
= showDoc
End SubPrivate Sub start
()If 源文件的目錄TextBox.
Text = "" Then源文件的目錄TextBox.
Text = 選擇目錄
()End IfIf MsgBox
("要處理的文件在:" & 源文件的目錄TextBox.
Text, vbYesNo
+ vbInformation
, "確認源文件目錄") <> vbYes
Then開始暫停ToggleButton.Caption
= "開 始"開始暫停ToggleButton.Value
= FalseExit SubEnd IfCall 遍歷文件夾中對文檔的關鍵字打標記
(源文件的目錄TextBox.
Text, 完成文件的目錄TextBox.
Text, 失敗文件的目錄TextBox.
Text, 跳過文件的目錄TextBox.
Text, 日志窗口TextBox
)
End SubPrivate Sub 開始暫停ToggleButton_Click
()If 開始暫停ToggleButton.Value
Then開始暫停ToggleButton.Caption
= "暫 停"Debug.
Print 開始暫停ToggleButton.Value
& "暫 停"Call start
Else開始暫停ToggleButton.Caption
= "開 始"Debug.
Print 開始暫停ToggleButton.Value
& "開 始"End IfEnd SubPrivate Sub csdn博客Label_Click
()Shell "cmd /c start https://jerryjin.blog.csdn.net/article/details/123596090", vbHide
End SubPrivate Sub 刷新目錄結構
(目標文件夾
As String, subLevel
As Integer)Call 更新文件夾結構信息
(目標文件夾
, subLevel
)子目錄深度ScrollBar.
Max = subFolderMaxLeveinfoLog
("======================獲取目錄結構成功======================")Call infoLog
(subFolderString
, "", "", "", vbCrLf
)End Sub
業務邏輯
遍歷文檔,查找替換的業務邏輯都在這。
遍歷文件使用了vba的 Dir("目標文件夾")方法。第一次目錄參數,第二次不帶參,就可以逐個返回下一文件,直到返回空字符串結束。移動文件使用了:Scripting.FileSystemObject輸出日志文件用的是 VBA的Shell "cmd.exe /c echo 日志內容 >> 日志文件", vbHide,第二個參數vbHide表示隱藏執行。
Option Explicit
Public Const SOURCE_FILE_PATH
As String = "sourceData\"
Public Const FINISHED_FILE_PATH
As String = "newData\"
Public Const ERROR_FILE_PATH
As String = "errorData\"
Public Const SKIP_FILE_PATH
As String = "skipData\"
Public Const DELIMS
As String = ","
Public Const DEFULT_REPLACEMENT_TEXT
As String = "^&"
Public Const STYLE_NAME
As String = "關鍵字"
Public Const DEL_FLAG
As String = "【del】" Public Const ERROR_FILE_SUFFIX
As String = "-Err.log"
Public Const SKIP_FILE_SUFFIX
As String = "-Skip.log"
Public Const SUCCESS_FILE_SUFFIX
As String = "-Success.log" Public successLogFile
As String
Public errLogFile
As String
Public skipLogFile
As String Public myConsole
As Object
Public showDoc
As Boolean Public subFolderArr
() As String
Public subFolderRelativePathArr
() As String
Public subFolderMaxLeve
As Integer
Public subFolderString
As String Public fs
As Object
Public wordApp
As Word.Application
Private keyArray
() As String
Private keyArrLen
As Integer Sub 遍歷文件夾中對文檔的關鍵字打標記
(sourceFilePath
As String, newPath
As String, errPath
As String, skipPath
As String, logTextBox
As Object)On Error GoTo ErrorHandler
Dim CurrFile$
, CurrFileName$
, currDoc
As Word.Document
, tempFileName
As String, pathLen
As Integer, path_i
As IntegerCall clearLog
Call infoLog
("1. 初始化 word 對象……")Set wordApp
= 獲取wordApp實例
()wordApp.Visible
= showDoc
Call infoLog
("2. 初始化 word 對象完成!^_^")
CurrFileName
= ThisWorkbook.
NameCall infoLog
("3. 定位當前文檔位置成功!")Set fs
= CreateObject
("Scripting.FileSystemObject")Call infoLog
("4. 獲取 FileSystemObject 成功!")If Dir
(newPath
, vbDirectory
) = vbNullString
Then Call 復制文件夾結構
(sourceFilePath
, newPath
) Call infoLog
("5. 成功文件目錄準備完畢!")If Dir
(skipPath
, vbDirectory
) = vbNullString
Then Call 復制文件夾結構
(sourceFilePath
, skipPath
) Call infoLog
("6. 跳過文件目錄準備完畢!")If Dir
(errPath
, vbDirectory
) = vbNullString
Then Call 復制文件夾結構
(sourceFilePath
, errPath
) Call infoLog
("7. 失敗文件目錄準備完畢!")keyArray
= 獲取關鍵字
()keyArrLen
= UBound(keyArray
)Call infoLog
("8. 加載關鍵字數據完成!")Call infoLog
("9. 開始處理文檔……")UserForm1.WebBrowser1.Visible
= TrueDim tempNewPath$
, tempSkipPath$
, tempErrPath$pathLen
= UBound(subFolderArr
)For path_i
= 0 To pathLensourceFilePath
= subFolderArr
(path_i
)tempNewPath
= newPath
& subFolderRelativePathArr
(path_i
)tempSkipPath
= skipPath
& subFolderRelativePathArr
(path_i
)tempErrPath
= errPath
& subFolderRelativePathArr
(path_i
)Call infoLog
(sourceFilePath
, "【開始處理文件夾】:", "", "", vbCrLf
)CurrFile
= Dir
(sourceFilePath
)Do Until CurrFile
= ""If Right(CurrFile
, 5) = ".docx" Or Right(CurrFile
, 4) = ".doc" ThentempFileName
= sourceFilePath
& CurrFile
Set currDoc
= wordApp.Documents.
Open(tempFileName
, Visible
:=showDoc
)If 對關鍵字打標記
(currDoc
) ThencurrDoc.SaveAs2 Filename
:=tempNewPath
& CurrFile
, FileFormat
:=wdFormatXMLDocument
Kill tempFileNamecurrDoc.
Close wdDoNotSaveChanges
Set currDoc
= Nothingsuccesslog tempFileNameUserForm1.成功數量TextBox.Value
= UserForm1.成功數量TextBox.Value
+ 1ElsecurrDoc.
Close wdDoNotSaveChanges
Set currDoc
= Nothingskiplog tempFileName
Call 移動文件
(tempFileName
, tempSkipPath
& CurrFile
)UserForm1.跳過數量TextBox.Value
= UserForm1.跳過數量TextBox.Value
+ 1End IfEnd If
NextFile
:DoEvents
If UserForm1.開始暫停ToggleButton.Value
= False ThenCall infoLog
("暫停中。。。。。。")wordApp.Quit
Exit SubEnd IfIf (0 + UserForm1.成功數量TextBox.Value
+ UserForm1.跳過數量TextBox.Value
+ UserForm1.失敗數量TextBox.Value
) Mod 2000 = 0 ThenCall infoLog
("優化性能:Word 重啟中。。。。。。")wordApp.Quit
Set wordApp
= NothingSet wordApp
= CreateObject
("Word.Application")wordApp.Visible
= showDoc
End IfCurrFile
= Dir
()LoopNextSet fs
= NothingwordApp.Visible
= TrueUserForm1.WebBrowser1.Visible
= FalseUserForm1.處理時顯示文檔CheckBox.Value
= TrueUserForm1.開始暫停ToggleButton.Caption
= "開 始"UserForm1.開始暫停ToggleButton.Value
= FalseCall MsgBox
("處理完畢,共處理 " & (0 + UserForm1.成功數量TextBox.Value
+ UserForm1.跳過數量TextBox.Value
+ UserForm1.失敗數量TextBox.Value
) & "個文檔!", vbOKOnly
+ vbInformation
, "溫馨提示")Exit Sub
ErrorHandler
:UserForm1.失敗數量TextBox.Value
= UserForm1.失敗數量TextBox.Value
+ 1errlog
"================================================================================"errlog
"【錯誤文件】" & tempFileNameerrlog Err.Number
& ":" & Replace
(Err.Description
, vbLf
, " vbCrLf ")Call 移動文件
(tempFileName
, tempErrPath
& CurrFile
)Resume NextFile
End SubFunction 對關鍵字打標記
(doc
As Word.Document
)
On Error GoTo ErrorHandler
Dim i
As Integer, edited
As Boolean Call 創建樣式
(doc
, STYLE_NAME
)For i
= 0 To keyArrLen
With doc.Content.Find.ClearFormatting.Replacement.ClearFormatting.Forward
= True.Wrap
= wdFindContinue.
Text = keyArray
(i
, 0).Replacement.
Text = keyArray
(i
, 1)If keyArray
(i
, 3) = "是" Then.Replacement.
Style = STYLE_NAME
Else.Replacement.ClearFormatting
End IfCall .Execute
(Replace
:=keyArray
(i
, 2))
NextKey
:If .Found
Then edited
= TrueEnd WithDoEvents
Next對關鍵字打標記
= edited
Exit Function
ErrorHandler
:errlog
"================================================================================"errlog
"【對關鍵字打標記出錯】" & keyArray
(i
, 0)errlog Err.Number
& ":" & Replace
(Err.Description
, vbLf
, " vbCrLf ")Resume NextKey
End FunctionFunction 創建樣式
(doc
As Word.Document
, styleName
As String)
On Error Resume Next Dim flag
As Booleanflag
= doc.Styles
(styleName
).NameLocal
= styleName
If flag
ThenExit FunctionEnd Ifdoc.Styles.Add
Name:=styleName
, Type:=wdStyleTypeCharacter
With doc.Styles
(styleName
).Font
.Bold
= True.
Color = wdColorYellow.Shading.ForegroundPatternColor
= wdColorAutomatic.Shading.BackgroundPatternColor
= wdColorRed
End WithEnd Function
Function 獲取關鍵字
() As String()Dim myRanges
As Range
, keyArray
() As String, arrLen
As Integer, i
As Integer, j
As Integer, dict
As ObjectSet dict
= CreateObject
("Scripting.Dictionary")Call dict.Add
("源字符", Range
("b1:e1").Find
("源字符").Column
- 1)Call dict.Add
("目標字符", Range
("b1:e1").Find
("目標字符").Column
- 1)Call dict.Add
("替換方式", Range
("b1:e1").Find
("替換方式").Column
- 1)Call dict.Add
("高亮", Range
("b1:e1").Find
("高亮").Column
- 1)arrLen
= Range
(Range
("B2"), Range
("B2").
End(xlDown
)).Rows.Count
Set myRanges
= Worksheets
("關鍵字").Range
(Range
("B2"), Range
("E2").Offset
(arrLen
- 1, 0))ReDim keyArray
(arrLen
- 1, 3) As StringFor i
= 0 To arrLen
- 1keyArray
(i
, 0) = myRanges
(i
+ 1, dict.Item
("源字符"))keyArray
(i
, 1) = myRanges
(i
+ 1, dict.Item
("目標字符"))If myRanges
(i
+ 1, dict.Item
("替換方式")) = "首個" ThenkeyArray
(i
, 2) = 1 ElsekeyArray
(i
, 2) = 2 End IfkeyArray
(i
, 3) = "是"Next i獲取關鍵字
= keyArray
End Function
Sub 移動文件
(sourcePath
As String, targetPath
As String)
On Error GoTo ErrorHandler
Call fs.moveFile
(sourcePath
, targetPath
)
Error_Handler_Exit
:Exit Sub
ErrorHandler
:errlog
"================================================================================"errlog
"【移動文件失敗】" & sourcePatherrlog Err.Number
& ":" & Replace
(Err.Description
, vbLf
, " vbCrLf ")Resume Error_Handler_Exit
End Sub
Function 獲取wordApp實例
()
On Error Resume NextSet 獲取wordApp實例
= GetObject
(, "Word.Application")If Err.Number
<> 0 ThenSet 獲取wordApp實例
= CreateObject
("Word.Application")End If
End Function
Sub errlog
(logMsg
As String)Shell "cmd.exe /c echo " & Format
(Now
, "YYYY-MM-DD HH:MM:SS") & " 》" & logMsg
& " >> " & errLogFile
, vbHide
Call infoLog
(logMsg
, "【失敗】:")
End Sub
Sub skiplog
(logMsg
As String)Shell "cmd.exe /c echo " & logMsg
& " >> " & skipLogFile
, vbHide
Call infoLog
(logMsg
, "【跳過】:")
End Sub
Sub successlog
(logMsg
As String)Shell "cmd.exe /c echo " & logMsg
& " >> " & successLogFile
, vbHide
Call infoLog
(logMsg
, "【成功】:")
End Sub
Sub infoLog
(logMsg
As String, Optional logType
As String = "【信息】:", Optional logTime
As String = "now", Optional logSeparator
As String = " ===》 ", Optional logEnd
As String = "")myConsole.
Text = myConsole
With myConsole.SetFocus.
Text = .
Text & vbCrLf
& logType
& VBA.IIf
(logTime
= "now", Format
(Now
, "YYYY-MM-DD HH:MM:SS"), logTime
) & logSeparator
& logMsg
& logEnd.SelStart
= Len(.Value
)End WithDoEvents
End Sub
Sub clearLog
()myConsole.
Text = ""
End Sub
工具模塊
遍歷文件夾,看了網上的方案感覺效率不太給力,這里直接調CMD命令曲線救國了。dir C:\原目錄 /b/s *.doc?批量拷貝目錄結構,不帶文件。xcopy C:\原目錄 C:\目標目錄 /t/i
Function 選擇目錄
()With Application.FileDialog
(msoFileDialogFolderPicker
).InitialFileName
= ThisWorkbook.path
& "\"If .Show
= -1 Then 選擇目錄
= .SelectedItems
(1)Else選擇目錄
= ""End IfEnd With
End FunctionFunction 統計字符串出現次數
(sourceStr
As String, searchStr
As String) As Long
On Error GoTo Error_Handler統計字符串出現次數
= UBound(Split
(sourceStr
, searchStr
))
Error_Handler_Exit
:Exit Function
Error_Handler
:Resume Error_Handler_Exit
End FunctionFunction 執行cmd命令
(cmdStr
As String) As String
On Error Resume NextDim oShell
As Object Dim oExec
As Object Set oShell
= CreateObject
("WScript.Shell")Set oExec
= oShell.Exec
("cmd /c " & cmdStr
)執行cmd命令
= oExec.StdOut.ReadAlloShell.Quit
Set oExec
= NothingSet oShell
= Nothing
End Function
Function 更新文件夾結構信息
(目標文件夾
As String, depth
As Integer) As String
On Error Resume NextDim arr
() As String, arrLen
As Integer, baseDepth
As String, i
As Integer, currDepth
As Integer, str As String目標文件夾
= VBA.IIf
(Right(目標文件夾
, 1) = "\", Left(目標文件夾
, Len(目標文件夾
) - 1), 目標文件夾
)baseDepth
= 統計字符串出現次數
(目標文件夾
, "\")str = 目標文件夾
& vbCrLf
& 執行cmd命令
("dir " & 目標文件夾
& " /ad /s /b")arr
= Split
(str, vbCrLf
)arrLen
= UBound(arr
)For i
= 0 To arrLencurrDepth
= 統計字符串出現次數
(arr
(i
), "\") - baseDepth
If Len(arr
(i
)) = 0 Or currDepth
> depth
Thenarr
(i
) = DEL_FLAG
Elsearr
(i
) = VBA.IIf
(Right(arr
(i
), 1) <> "\", arr
(i
) & "\", arr
(i
))End IfsubFolderMaxLeve
= VBA.IIf
(currDepth
> subFolderMaxLeve
, currDepth
, subFolderMaxLeve
)Nextarr
= Filter
(arr
, DEL_FLAG
, False, vbTextCompare
)subFolderArr
= arrsubFolderString
= Join
(subFolderArr
, vbCrLf
)subFolderRelativePathArr
= Split
(Replace
(subFolderString
, 目標文件夾
& "\", ""), vbCrLf
)更新文件夾結構信息
= subFolderString
End FunctionFunction 復制文件夾結構
(原文件夾
As String, 目標文件夾
As String)Call 執行cmd命令
("xcopy " & 原文件夾
& " " & 目標文件夾
& " /t/i")
End FunctionFunction 移除末尾空行
(myString
As String)If Len(myString
) > 0 ThenIf Right$(myString
, 2) = vbCrLf
Or Right$(myString
, 2) = vbNewLine
ThenmyString
= Left$(myString
, Len(myString
) - 2)End IfEnd If移除末尾空行
= myString
End Function
性能優化
暫時感覺不出來。。。目前越來越慢的是word,但是又好像有當前這個Excel有關系。
Public CalcState
As Long
Public EventState
As Boolean
Public PageBreakState
As Boolean
Sub OptimizeCode_Begin
(app
As Object)
On Error Resume Nextapp.ScreenUpdating
= FalseEventState
= app.EnableEventsapp.EnableEvents
= FalseCalcState
= app.Calculationapp.Calculation
= xlCalculationManualPageBreakState
= ActiveSheet.DisplayPageBreaksActiveSheet.DisplayPageBreaks
= False
End Sub
Sub OptimizeCode_End
(app
As Object)
On Error Resume NextActiveSheet.DisplayPageBreaks
= PageBreakStateapp.Calculation
= CalcStateapp.EnableEvents
= EventStateapp.ScreenUpdating
= True
End Sub
Sheet1(關鍵字)(工作表按鈕事件)
表格中添加了一個按鈕,用于打開窗口
Private Sub CommandButton1_Click
()UserForm1.Show
End Sub
ThisWorkbook(工作簿事件)
打開工作簿后自動彈出窗口
Private Sub Workbook_Activate
()UserForm1.Show
End Sub
引用 word
因為聲明了word對象,需要引用一下庫。
源文件
下載↑↑↑頂部預覽圖,用解壓工具打開即可。
參考資料
How to fit image size on excel WebBrowser control
Word實現的那個舊版 —— VBA 收集 Word關鍵字批量處理
總結
以上是生活随笔為你收集整理的VBA 收集 Word关键字批量处理-Excel版的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。