Link to home
Start Free TrialLog in
Avatar of excelismagic
excelismagic

asked on

Challenge to VBA masters (VBA to find and replace and save and close files)

I have Word documents and Excel files.

formats are  xls  , xlsb,  xlsm,  xlsx , doc,   docm,  docx

these files are in a folder, where i can get a pop window to select the folder, so then the VBA looks in reach folder and its subfolders and finds any file with the above mentioned format and if found, then searches inside the file,  for the following Texts

"PRF54", "HGR541" ,"5415" , "HHHE87"  if any of these searched files had these values in Cell of Excel or paragraph of Word, then replace them with "PRRF51", "HGR111" "4154" , "HHRE77"

then at the end to show what Range/cell in Excel or what page number in word had these values and have many of them were found and repalced.

i have alot of manual work, if i do not have this VBA help. i greatly appreciate it.
Avatar of aikimark
aikimark
Flag of United States of America image

show what Range/cell in Excel or what page number
Does that mean that there will only ever be a single instance of one of those strings in any single file?
Avatar of excelismagic
excelismagic

ASKER

thank you very much aikimark for looking into this.

yes, it could be single or multiple but will not be more than 3 in each file.
Can't work this today, but a few thoughts passing by.

- Do you want the find to be case sensitive?

- Could your search strings ever be part of a larger string that you don't want to replace?  For example, you want to look for "5415", but what if the string "54159" existed in the file.  Would you want the first 4 characters of that replaced, ending up with "41549"?

- There are no page numbers in a word file until you print it (or view in a paginated mode), so not sure you can report that.

- Do you want to overwrite the original files, or place the updated copies someplace else?

- Could the Excel (or Word) file ever be password protected, and if so how do you want to deal with that?

~bp
thank you very much Bill.

answer to the questions

- Do you want the find to be case sensitive?
 yes it is case sensitive

Could your search strings ever be part of a larger string that you don't want to replace?  For example, you want to look for "5415", but what if the string "54159" existed in the file.  Would you want the first 4 characters of that replaced, ending up with "41549"?
yes, even if it is part of larger part, i still want the replace to happen. for example the first 4 char to be replaced.

There are no page numbers in a word file until you print it (or view in a paginated mode), so not sure you can report that.
if there is no page, then only file name and path suffices

Do you want to overwrite the original files, or place the updated copies someplace else?
 this is a great idea, if i can place the updated file in another folder and do not overwrite the existing ones.  is this possible? if yes, this is even better.

Could the Excel (or Word) file ever be password protected, and if so how do you want to deal with that?
 my files are not protected.
This code could be helpful, though it doesn't do replacements, just finds:

Private Sub cmdWordSearch_Click()
'Created by Helen Feddema 5-Jun-2014
'Last modified by Helen Feddema 17-Aug-2014

On Error GoTo ErrorHandler

   Dim docSearch As Word.Document
   Dim fso As New Scripting.FileSystemObject
   Dim intFindCount As Integer
   Dim strFindText As String
   Dim strTable As String
   
   'Check that a word or phrase has been entered
   Set txt = Me![txtSearchPhrase]
   strFindText = Nz(txt.Value)
   strTable = "tblWordSearch"
   
On Error Resume Next
   
   DoCmd.Close acTable, strTable
   
On Error GoTo ErrorHandler

   strSQL = "DELETE * FROM " & strTable
   CurrentDb.Execute strSQL, dbFailOnError
   
   If strFindText = "" Then
      strTitle = "No search phrase entered"
      strPrompt = "Please enter a search word or phrase"
      MsgBox prompt:=strPrompt, _
         Buttons:=vbInformation + vbOKOnly, _
         Title:=strTitle
      txt.SetFocus
      GoTo ErrorHandlerExit
   End If
   
   intChoice = Nz(Me![fraSearchPhrase].Value, 1)
   Set appWord = GetObject(, "Word.Application")
   appWord.Visible = False
   Call CloseAllWordDocs

   If intChoice = 1 Then
      'Select a Word document or template to process
      'Create a FileDialog object as a File Picker dialog box.
      Set fd = Application.FileDialog(msoFileDialogFilePicker)
      
      With fd
         .AllowMultiSelect = False
         .Title = "Browse for a Word document or template"
         .ButtonName = "Select"
         .Filters.Clear
         .Filters.Add Description:="Document or template", _
            Extensions:="*.doc; *.docx; *.docm; *.dot; *.dotx; *.dotm", _
            Position:=1
         .InitialView = msoFileDialogViewDetails
         If .Show = -1 Then
            'Get selected item in the FileDialogSelectedItems collection
            For Each varSelectedItem In .SelectedItems
               strFileNameAndPath = CStr(varSelectedItem)
            Next varSelectedItem
         Else
            Debug.Print "User pressed Cancel"
            strFileNameAndPath = ""
            GoTo ErrorHandlerExit
         End If
      End With
      
      Debug.Print "Selected Word doc: " & strFileNameAndPath
      
      Set docSearch = appWord.Documents.Open(strFileNameAndPath)
      docSearch.Select
      intFindCount = 0
      
      With appWord.Selection.Find
         .ClearFormatting
         .Execute findtext:=strFindText
         While .Found = True
            intFindCount = intFindCount + 1
            .Execute
         Wend
      End With
      
      'MsgBox "Found " & intFindCount & " instances of " & strFindText
      Set rst = CurrentDb.OpenRecordset(strTable)
      
      With rst
         .AddNew
         ![DocumentName] = strFileNameAndPath
         ![SearchPhrase] = strFindText
         ![FindCount] = intFindCount
         .Update
      End With
      
      docSearch.Close savechanges:=wdDoNotSaveChanges
      
   ElseIf intChoice = 2 Then
      'Select a folder of documents to process
      'Create a FileDialog object as a Folder Picker dialog box
      lngSelectCount = 0
      Set fd = Application.FileDialog(msoFileDialogFolderPicker)
      
      With fd
         .Title = "Browse for folder containing Word documents to process"
         .ButtonName = "Select"
         .InitialView = msoFileDialogViewDetails
         .InitialFileName = strPath
         If .Show = -1 Then
            strPath = CStr(fd.SelectedItems.Item(1))
            Debug.Print "Selected folder: " & strPath
            Set fld = fso.GetFolder(strPath)
         Else
            strPath = ""
            GoTo ErrorHandlerExit
         End If
      End With
      
      lngSelectCount = fld.Files.Count
      Debug.Print "Number of files in folder: " & lngSelectCount
      strProgressBarText = "Processing documents... "
      Call SysCmd(acSysCmdInitMeter, strProgressBarText, _
         lngSelectCount)
      lngCount = 0
      
      For Each fil In fld.Files
         'Debug.Print "Examining " & fil.Name
         'Debug.Print "Contains 'Copy'? " & Nz(InStr(fil.Name, "Copy"))
         'Debug.Print "1st character: " & Left(fil.Name, 1)
         
         If (Right(fil.Name, 3) = "doc" Or Right(fil.Name, 4) = "docx" _
            Or Right(fil.Name, 3) = "dot" Or Right(fil.Name, 4) = "dotx") _
            And (Left(fil.Name, 1) <> "~" _
            And Nz(InStr(fil.Name, "Copy")) = 0) Then
            strFileNameAndPath = strPath & "\" & fil.Name
            Debug.Print "File to process: " & strFileNameAndPath
            Set docSearch = appWord.Documents.Open(strFileNameAndPath)
            docSearch.Select
            intFindCount = 0
            
            With appWord.Selection.Find
               .ClearFormatting
               .Execute findtext:=strFindText
               While .Found = True
                  intFindCount = intFindCount + 1
                  .Execute
               Wend
            End With
            
            'MsgBox "Found " & intFindCount & " instances of " & strFindText
            Set rst = CurrentDb.OpenRecordset(strTable)
            
            With rst
               .AddNew
               ![DocumentName] = strFileNameAndPath
               ![SearchPhrase] = strFindText
               ![FindCount] = intFindCount
               .Update
            End With
            
            lngCount = lngCount + 1
            Debug.Print "Count: " & lngCount
            Call SysCmd(acSysCmdUpdateMeter, lngCount)

          End If
CheckNext:
      Next fil
      
      strTitle = "Done"
      strPrompt = lngCount & " documents searched in " & strPath
      MsgBox prompt:=strPrompt, _
         Buttons:=vbInformation + vbOKOnly, _
         Title:=strTitle
      Call SysCmd(acSysCmdRemoveMeter)
     
   End If
         
   DoCmd.OpenTable TableName:=strTable
      
ErrorHandlerExit:
   Set appWord = Nothing
   Set docSearch = Nothing
   Set fso = Nothing
   
   Exit Sub

ErrorHandler:
   If Err.Number = 4605 Then
      GoTo CheckNext
   Else
      MsgBox "Error No: " & Err.Number _
         & " in " & Me.ActiveControl.Name & " procedure; " _
         & "Description: " & Err.Description
      Resume ErrorHandlerExit
   End If
   
End Sub

Open in new window


The choice is whether to search a single selected document, or all documents in a selected folder.  This code is from the sample database for my Working with Word ebook, available from Office Watch.
thanks Helen,

as i stated, i need to do replacement, not just find. besides you code states invalid use of Me Key in line Set txt = Me![txtSearchPhrase
This code runs from a form, so the Me keyword is fine.  It is used here to set a Textbox variable.
ASKER CERTIFIED SOLUTION
Avatar of Professor J
Professor J

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Excellent free tool. thanks.