Remove illegal characters while saving workbook Excel VBA - vba

this code basically reformats an xls file and saves it as an xlsx. however it uses G2 & H2 to grab the filename for the newly formatted file.
So that means certain characters can't be in the file name. I added a chunk of code to replace those characters (
' Remove/Replace Invalid File Name Characters
WkbName = Range("H2")
MyArray = Array("<", ">", "|", "/", "*", "\", ".", "?", """")
For X = LBound(MyArray) To UBound(MyArray)
WkbName = Replace(WkbName, MyArray(X), "_", 1)
Next X
'MsgBox WkbName 'dispaly file name with illegal characters removed
ActiveWorkbook.SaveAs Filename:= _
WBPath & "\BOM_" & Range("G2") & "_" & WkbName & ".xlsx" _
, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
)
activeworkbook.saves as is where the debugger always takes me
I'm getting an error message saying there's always an illegal character even if its just normal text in h2, am I missing something?
full code below
Sub FormatBOMExport()
'
' FormatBOMExportPnV Macro
'
Application.ScreenUpdating = False
Application.DisplayAlerts = False
' delete extra sheets
Sheets(Array("Sheet2", "Sheet3")).Select
ActiveWindow.SelectedSheets.Delete
WBPath = Application.ActiveWorkbook.Path
OrgFile = Application.ActiveWorkbook.FullName
Range("B1").Select
With Selection
.HorizontalAlignment = xlGeneral
.VerticalAlignment = xlBottom
.WrapText = True
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
Columns("A:M").Select
Selection.Replace What:="" & Chr(10) & "", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Selection.Columns.AutoFit
Selection.Rows.AutoFit
Columns("J:J").Select
With Selection
.HorizontalAlignment = xlGeneral
.VerticalAlignment = xlBottom
.WrapText = True
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
' Columns("J:J").Select
' Columns("J:J").ColumnWidth = 100
' Selection.Rows.AutoFit
Columns("G:G").EntireColumn.AutoFit
Range("G2").Select
' Remove/Replace Invalid File Name Characters
WkbName = Range("H2")
MyArray = Array("<", ">", "|", "/", "*", "\", ".", "?", """")
For X = LBound(MyArray) To UBound(MyArray)
WkbName = Replace(WkbName, MyArray(X), "_", 1)
Next X
'MsgBox WkbName 'dispaly file name with illegal characters removed
ActiveWorkbook.SaveAs Filename:= _
WBPath & "\BOM_" & Range("G2") & "_" & WkbName & ".xlsx" _
, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
If Len(Dir$(OrgFile)) > 0 Then
Kill OrgFile
End If
Application.DisplayAlerts = True
Application.ScreenUpdating = True
' MsgBox OrgFile & " has been deleted and saved as " & "BOM_" & Range("G2") & "_" & Range("H2") & ".xlsx"
End Sub
`
please excuse my notes and random crap in the code. I always clean it up before I give it to others

Because there could be more illegal characters in the filename. Your approach is right but it's not comprehensive list of illegal characters to remove or replace from the filename before saving it. For eg. these characters are missing from the array in your code -> : & . However it is advised to keep filename rid of other allowed special characters too.
Below, I am providing the function which returns a safe string that can be used to produce filename before saving.
Function ReplaceIllegalCharacters(strIn As String, strChar As String) As String
Dim strSpecialChars As String
Dim i As Long
strSpecialChars = "~""#%&*:<>?{|}/\[]" & Chr(10) & Chr(13)
For i = 1 To Len(strSpecialChars)
strIn = Replace(strIn , Mid$(strSpecialChars, i, 1), strChar)
Next
ReplaceIllegalCharacters = strIn
End Function
Specifically, in your code, replace the ActiveWorkbook.SaveAs line with this line:
ActiveWorkbook.SaveAs Filename:= _
WBPath & "\BOM_" & Range("G2").Value2 & "_" & ReplaceIllegalCharacters(Range("H2").Value2, "_") & ".xlsx" _
, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False

Related

Macro runs on PC but not on MacOS: Subscript out of range error

I can get this code to run on PC but not on Mac. The code allows you to select text files and convert them into worksheets and append them to your current workbook.
Set wkbTemp = Workbooks.Open(FileName:=FilesToOpen(x))
The above line of code is sending the program to the Error Handler and causing a subscript out of range error.
In the link below is a picture of the Locals Window that shows the path name from the file I wish to grab.
https://imgur.com/a/wPzH5VB
Sub CombineTextFiles()
Dim FilesToOpen
Dim x As Integer
Dim wkbAll As Workbook
Dim wkbTemp As Workbook
Dim sDelimiter As String
Dim answer As Integer
On Error GoTo ErrHandler
Application.ScreenUpdating = False
answer = MsgBox("Before moving forward, all other workbooks must be closed" _
& vbCrLf & "Do you wish to continue?", vbYesNo + vbQuestion)
If answer = vbYes Then 'do nothing
Else: Exit Sub
End If
sDelimiter = ","
#If Mac Then
FilesToOpen = Select_File_Or_Files_Mac()
#Else
FilesToOpen = Application.GetOpenFilename(fileFilter:="Text Files (*.txt), *.txt", _
MultiSelect:=True, Title:="Select the CDR Text Files to Open")
#End If
If TypeName(FilesToOpen) = "Boolean" Then
MsgBox "No Files were selected"
GoTo ExitHandler
End If
x = 1
Set wkbTemp = Workbooks.Open(FileName:=FilesToOpen(x))
wkbTemp.Sheets(1).Copy
Set wkbAll = ActiveWorkbook
wkbTemp.Close (False)
wkbAll.Worksheets(x).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:=","
x = x + 1
While x <= UBound(FilesToOpen)
Set wkbTemp = Workbooks.Open(FileName:=FilesToOpen(x))
With wkbAll
wkbTemp.Sheets(1).Move After:=.Sheets(.Sheets.Count)
.Worksheets(x).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:=sDelimiter
End With
x = x + 1
Wend
wkbAll.Sheets.Copy After:=Workbooks(2).Sheets(Workbooks(2).Worksheets.Count)
wkbAll.Close False
ExitHandler:
Application.ScreenUpdating = True
Set wkbAll = Nothing
Set wkbTemp = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description
Resume ExitHandler
End Sub
Function Select_File_Or_Files_Mac() As String()
Dim MyPath As String
Dim MyScript As String
Dim MyFiles As String
Dim MySplit As Variant
Dim N As Long
Dim FName As String
Dim mybook As Workbook
On Error Resume Next
MyPath = MacScript("return (path to documents folder) as String")
'Or use MyPath = "Macintosh HD:Users:Ron:Desktop:TestFolder:"
' In the following statement, change true to false in the line "multiple
' selections allowed true" if you do not want to be able to select more
' than one file. Additionally, if you want to filter for multiple files, change
' {""com.microsoft.Excel.xls""} to
' {""com.microsoft.excel.xls"",""public.comma-separated-values-text""}
' if you want to filter on xls and csv files, for example.
MyScript = _
"set applescript's text item delimiters to "","" " & vbNewLine & _
"set theFiles to (choose file of type " & _
" {""com.microsoft.excel.xls"",""public.comma-separated-values-text"", ""public.text""} " & _
"with prompt ""Please select a file or files"" default location alias """ & _
MyPath & """ multiple selections allowed true) as string" & vbNewLine & _
"set applescript's text item delimiters to """" " & vbNewLine & _
"return theFiles"
MyFiles = MacScript(MyScript)
Dim returnList() As String
On Error GoTo 0
If MyFiles <> "" Then
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'MsgBox MyFiles
MySplit = Split(MyFiles, ",")
ReDim returnList(LBound(MySplit) To UBound(MySplit))
For N = LBound(MySplit) To UBound(MySplit)
returnList(N) = MySplit(N)
Next N
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
Select_File_Or_Files_Mac = returnList
Else
ReDim returnList(0 To 0)
returnList(0) = "False"
Select_File_Or_Files_Mac = returnList
End If
End Function
Both Application.GetOpenFilename and Select_File_Or_Files_Mac return an array of one or more file names, but the first array is one-based, and your Mac version is zero-based.
Your counter x starts at 1, so it's already out of range for a "mac" array with only one file: i.e. FilesToOpen(0)
You can modify your Mac code to return a one-based array.
Modify this part:
MySplit = Split(MyFiles, ",")
ReDim returnList(1 to To UBound(MySplit)+1) 'one-based not zero-based...
For N = LBound(MySplit) To UBound(MySplit)
returnList(N + 1) = MySplit(N)
Next N
...and this part:
ReDim returnList(1 To 1)
returnList(1) = "False"

Query Relative Path for Folder.Files

Excel 2016 VBA, Windows 10
I'm trying to use VBA to Get Data. I want to use a relative reference. I just want to get data from 'Raw Keyword.csv' in the same folder as the xlsm file. It never seems to recognize the relative path. I tried building it with all the quotes around it (option A, preferred) and passing that variable to Folder.Files. I saw a suggestion to put the Path and filename in File.Contents in another thread (link below) but that didn't work either. Any suggestions?
' Option A
Dim RawK As String
RawK = """""" & ActiveWorkbook.Path & "\Raw Keyword.csv" & """"""
ActiveWorkbook.Queries.Add Name:="Query Keyword", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " Source = Csv.Document(File.Contents(RawK)...
' Option B:
ActiveWorkbook.Queries.Add Name:="Query Keyword", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " Source = Csv.Document(File.Contents(ActiveWorkbook.Path & ""\Raw Keyword.csv"") ...
Saw a similar answer here, but no luck with that.
Relative path for Folder.Files
I think this is what you're looking for:
Sub tgr()
Dim CSVName As String
Dim qt As Object
CSVName = "Raw Keyword"
On Error Resume Next
Set qt = ActiveWorkbook.Connections(CSVName)
On Error GoTo 0
If qt Is Nothing Then
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & ActiveWorkbook.Path & "\" & CSVName & ".csv", Destination:=Range("$A$1"))
.FieldNames = True
.RefreshOnFileOpen = True
.RefreshStyle = xlInsertDeleteCells
.AdjustColumnWidth = True
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileCommaDelimiter = True
.Refresh BackgroundQuery:=False
End With
Else
qt.Refresh
End If
End Sub

Refresh BackgroundQuery VBA

Sub OPInport(month As Integer, year As Integer)
'
' Macro6 Macro
'F und G
'
Dim selectedRange As Date
Dim WrkBook As Workbook
Dim WrkSheet As Worksheet
Set WrkBook = ActiveWorkbook
Set WrkSheet = ActiveSheet
selectedRange = DateSerial(year, month, 1)
MsgBox selectedRange
WrkBook.Sheets(1).Columns("G:H").NumberFormat = "dd.mm.yyyy"
Range("$A$1").Value = "Change"
Application.CutCopyMode = False
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"ODBC;DSN=OpsApps;UID=Alligatoah;Trusted_Connection=Yes;APP=Microsoft Office 2016;WSID=AT000616;DATABASE=OpsApps" _
, Destination:=Range("$B$1")).QueryTable
.CommandText = Array( _
"SELECT IPM_V_TV_URB.Customer, IPM_V_TV_URB.KNUM, IPM_V_TV_URB.DMRF, IPM_V_TV_URB.HeaderBoM, IPM_V_TV_URB.ProgramReleasedCosts, IPM_V_TV_URB.PlnLaunch, IPM_V_TV_URB.SystemSDate, IPM_V_TV" _
, _
"_URB.ActualCosts" & Chr(13) & "" & Chr(10) & "FROM OpsApps.dbo.IPM_V_TV_URB IPM_V_TV_URB" & Chr(13) & "" & Chr(10) & "WHERE (IPM_V_TV_URB.SystemSDate>={ts selectedRange & 00:00:00'})" _
)
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "Table_Query_from_OpsApps"
.Refresh BackgroundQuery:=False
End With
I want to select a specific range of data, but when i try to do that it says "Runtime Error 1004 General ODBC Error" and points out the last line, .Refresh BackgroundQuery:=False. Im quite new to VBA and cant really find a solution to the problem. It only started showing that error message when i changed the date in the where question with selectedDate.
You need to concatenate the selected date into your string - what you are doing currently is using the literal name of the variable as a date.
"_URB.ActualCosts" & Chr(13) & "" & Chr(10) & "FROM OpsApps.dbo.IPM_V_TV_URB IPM_V_TV_URB" & Chr(13) & "" & Chr(10) & "WHERE (IPM_V_TV_URB.SystemSDate>={ts '" & Format(selectedRange, "yyyy-mm-dd") & " 00:00:00'})"
You may need to change the date format used.

Open the excel new file after complete operation

hi what i am doing right now is scrapping data. after the process complete it will pop msgbox "Completed" and the new file contains the data will be save to network path. my question is. what code do i need to add so that. after the scraping operation complete, it will automatically open the new file created by the scrap tool.
Here is my code
Global FilePath As String
Global strPath As String
Declare Function WNetGetUser Lib "mpr.dll" _
Alias "WNetGetUserA" (ByVal lpName As String, _
ByVal lpUserName As String, lpnLength As Long) As Long
Const NoError = 0
Sub Clear_Internet_Cache()
Shell "RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess 255"
End Sub
''==========================================================================================
''Copy_Paste function creates the log of excel files with the issues in it
''==========================================================================================
Function Copy_Paste() As String
Dim SourceBook As Workbook
Dim DBook As Workbook
Dim strPath As String
Dim count As Double
Dim name As String
Dim TemplateBook, MyTime, Mydate As String
Dim FileName As String
Dim directoryName As String
Dim FY1 As String
Dim WK As String
Dim MyInput As Integer
Dim layer As String
Dim CrawlerName As String
Dim fixedpath As String
Dim region As String
Dim segment As String
If Sheet1.Cells(2, 6) = "Upload to Sharedrive" Then
fixedpath = "\\"
FY1 = Sheet1.Cells(2, 7)
WK = Sheet1.Cells(2, 8)
MyInput = Sheet9.Cells(3, 26)
CrawlerName = "AIO"
region = "EMEA"
segment = Sheet1.Cells(2, 9)
If MyInput = 1 Then
layer = "Staging"
Else
layer = "Production"
End If
''''''''''''''''''''''''''''''FOR USER NAME
Const lpnLength As Integer = 255
Dim status As Integer
Dim lpName, lpUserName As String
lpUserName = Space$(lpnLength + 1)
status = WNetGetUser(lpName, lpUserName, lpnLength)
If status = NoError Then
lpUserName = Left$(lpUserName, InStr(lpUserName, Chr(0)) - 1)
End If
'''''''''''''''''''''''''''''''''''''''''''
directoryName = fixedpath & "\" & region
If Not DirExists(directoryName) Then
MkDir (directoryName)
End If
directoryName = fixedpath & "\" & region & "\" & segment
If Not DirExists(directoryName) Then
MkDir (directoryName)
End If
directoryName = fixedpath & "\" & region & "\" & segment & "\" & FY1
If Not DirExists(directoryName) Then
MkDir (directoryName)
End If
directoryName = fixedpath & "\" & region & "\" & segment & "\" & FY1 & "\" & WK
If Not DirExists(directoryName) Then
MkDir (directoryName)
End If
directoryName = fixedpath & "\" & region & "\" & segment & "\" & FY1 & "\" & WK & "\" & layer
If Not DirExists(directoryName) Then
MkDir (directoryName)
End If
directoryName = fixedpath & "\" & region & "\" & segment & "\" & FY1 & "\" & WK & "\" & layer & "\" & CrawlerName
If Not DirExists(directoryName) Then
MkDir (directoryName)
End If
strPath = directoryName
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
TemplateBook = "AIO_Report"
TemplateBook = Left(TemplateBook, Len(TemplateBook) - 5)
Mydate = Format(Date, "mmm d yyyy")
MyTime = Format(Time, "hh:mm:ss")
MyTime = Replace(MyTime, ":", "_")
FileName = TemplateBook & "_" & Mydate & "_" & MyTime
FilePath = ""
FilePath = strPath & "\" & FileName & "_" & lpUserName & ".xlsx"
Set SourceBook = ActiveWorkbook
Set DBook = Workbooks.Add
SourceBook.Sheets("Bundle List").Cells.copy Destination:=DBook.Sheets("Sheet1").Cells
DBook.Sheets("Sheet1").name = "Error Report"
Sheets("Error Report").Select
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
Range("A1").Select
Selection.EntireRow.Select
Selection.Delete
Range("A1").Select
Selection.EntireRow.Select
Selection.Delete
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
DBook.SaveCopyAs FilePath
DBook.Close False
End If
Sheets("Bundle List").Select
Columns("W:An").Select
Selection.Delete Shift:=xlToLeft
Columns("a").Select
MsgBox ("Completed.")
Application.StatusBar = ""
End Function
If DBook is the file you want left open, then I'd probably change this:
DBook.SaveCopyAs FilePath
DBook.Close False
To:
DBook.SaveAs FilePath
This will leave the workbook open, and you've already saved it. Just keep it open for the user to have their way with. As for SaveCopyAs don't think you need to save a copy of an unsaved workbook, right? Have fun!
Assuming you saved some file such as "xyz.xlsx",
call something like
Shell("cmd /c ..pathto...xyz.xlsx")
what it will do is to launch cmd prompt as a conduit to launching the program
registered for xlsx. It will work for any registered extension such as pdf.

List of all files in Folder / Sub Folder with Hyperlink

I am using this code to list out files in folder and sub-folder. The code is working fine. But if there is no sub-folder I get an error in the below line.
'Files under current dir
fname = Dir(fPath & "*." & fType).
And I want message-box option (Yes/no) for empty folders. (Currently its showing all empty folders)
Public oldNR As Long
Sub HyperlinkDirectory()
Dim fPath As String
Dim fType As String
Dim fname As String
Dim NR As Long
Dim AddLinks As Boolean
'Select folder
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.InitialFileName = "C:\2009\"
.Show
If .SelectedItems.Count > 0 Then
fPath = .SelectedItems(1) & "\"
Else
Exit Sub
End If
End With
'Types of files
fType = Application.InputBox("What kind of files? Type the file extension to collect" _
& vbLf & vbLf & "(Example: xls, doc, txt, pdf, *)", "File Type", "PDF", Type:=2)
If fType = "False" Then Exit Sub
'Option to create hyperlinks
AddLinks = MsgBox("Add hyperlinks to the file listing?", vbYesNo) = vbYes
'Create report
Application.ScreenUpdating = False
NR = 4
With ActiveSheet
.Range("A:C").Clear
.[A2] = "LIST OF FILES"
.[B2] = "Modified Date"
Call FindFilesAndAddLinks(fPath, fType, NR, AddLinks)
End With
With ActiveSheet
.Range("A:B").Columns.AutoFit
.Range("B:B").HorizontalAlignment = xlCenter
Range("B:B").Select
Selection.NumberFormat = "d-mmm-yy h:mm AM/pm"
End With
With ActiveSheet
Range("A2").Select
Selection.Font.Bold = True
Range("B2").Select
Selection.Font.Bold = True
Columns("A:A").Select
Selection.Font.Underline = xlUnderlineStyleNone
End With
Application.ScreenUpdating = True
End Sub
Private Sub FindFilesAndAddLinks(fPath As String, fType As String, ByRef NR As Long, AddLinks As Boolean)
Dim fname As String
Dim oFS As New FileSystemObject
Dim oDir
'Files under current dir
fname = Dir(fPath & "*." & fType)
With ActiveSheet
'Write folder name
.Range("A" & NR) = fPath
.Range("A" & NR).Select
If AddLinks Then .Hyperlinks.Add Anchor:=Selection, _
Address:=fPath, _
TextToDisplay:="FOLDER NAME: " & " " & UCase(Split(fPath, "\")(UBound(Split(fPath, "\")) - 1))
Selection.Font.Bold = True
Selection.Font.Size = 10
Selection.Font.Name = "Arial"
Selection.Font.Underline = xlUnderlineStyleNone
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent3
.TintAndShade = 0.399975585192419
.PatternTintAndShade = 0
End With
With Selection.Font
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
End With
NR = NR + 2
Do While Len(fname) > 0
'filename
If .Range("A" & NR) <> "" Then Debug.Print "Overwriting " & NR
.Range("A" & NR) = fname
'modified
.Range("B" & NR) = FileDateTime(fPath & fname)
'hyperlink
.Range("A" & NR).Select
If AddLinks Then .Hyperlinks.Add Anchor:=Selection, _
Address:=fPath & fname, _
TextToDisplay:=fname
'set for next entry
NR = NR + 1
fname = Dir
Loop
'Files under sub dir
Set oDir = oFS.GetFolder(fPath)
For Each oSub In oDir.SubFolders
NR = NR + 1
Call FindFilesAndAddLinks(oSub.Path & "\", fType, NR, AddLinks)
Next oSub
End With
ActiveWindow.DisplayGridlines = False
End Sub