So, I have a macro to export data into CSV format and it's working great (Code at the bottom). The problem is the data I am putting into it. When I put the data in question in it comes out
Firstname,Lastname,username,password,description
I'd like to change it so I get
Firstname Lastname,Firstname,Lastname,username,password,description
What I'd like to do is manipulate the existing macro so to accomplish this. I'm not so good at VBS so any input or a shove in the right direction would be fantastic.
Thanks!
The code is from user Chance2 http://www.excelforum.com/excel-programming/679620-set-up-macro-to-export-as-csv-file.html. Fair is fair and the author should be rightly attributed. I apologize for making any of this sound proprietary.
Sub Make_CSV()
Dim sFile As String
Dim sPath As String
Dim sLine As String
Dim r As Integer
Dim c As Integer
r = 1 'Starting row of data
sPath = "C:\CSVout\"
sFile = "MyText_" & Format(Now, "YYYYMMDD_HHMMSS") & ".CSV"
Close #1
Open sPath & sFile For Output As #1
Do Until IsEmpty(Range("A" & r))
'You can also Do Until r = 17 (get the first 16 cells)
sLine = ""
c = 1
Do Until IsEmpty(Cells(1, c))
'Number of Columns - You could use a FOR / NEXT loop instead
sLine = sLine & """" & Replace(Cells(r, c), ";", ":") & """" & ","
c = c + 1
Loop
Print #1, Left(sLine, Len(sLine) - 1) 'Remove the trailing comma
r = r + 1
Loop
Close #1
End Sub
Simplest change would be to assign sLine with the 'Firstname Lastname' concatenation i.e.:
Do Until IsEmpty(Range("A" & r))
'You can also Do Until r = 17 (get the first 16 cells)
sLine = """" & Replace(Cells(r,1) & " " & Cells(r,2), ";", ":") + ""","
c = 1
Do Until IsEmpty(Cells(1, c))
'Number of Columns - You could use a FOR / NEXT loop instead
sLine = sLine & """" & Replace(Cells(r, c), ";", ":") & """" & ","
c = c + 1
Loop
Print #1, Left(sLine, Len(sLine) - 1) 'Remove the trailing comma
r = r + 1
Loop
Related
On Error Resume Next
Set FileSysObj = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1 ' Declare constant for reading for more clarity
Dim cntFile, strCSVFullFile, strCSVFile, strDIR, cntBadLines, cntAllLines, strArchiveDir, strSafeTime,strSafeDate
' -------------------------------------------------------------------------------------------
' Specify CSV file name from the input argument
strCSVFile = Wscript.Arguments(1) ' Transactions
strDIR = Wscript.Arguments(2) & "\" ' C:\Temp
strArchiveDir = Wscript.Arguments(3) & "\"
strSafeTime = Right("0" & Hour(Now), 2) & Right("0" & Minute(Now), 2) & Right("0" & Second(Now), 2)
strSafeDate = Year(Date) & Month(Date) & day(Date)
set folder = FileSysObj.getFolder(strDIR)
cntFile = 0
cntBadLines = 0
cntAllLines = 0
for each file in folder.Files
' check if the file is there and echo it.
if InStr(1,file.name,strCSVFile,1) <> 0 then
strCSVFullFile = file.name
cntFile = cntFile + 1
end if
next
if cntFile > 1 or cntFile = 0 then
' error and end
Wscript.Echo "Error - only 1 file required for this process. There are " & cntFile & " file(s) in the directory"
WScript.Quit
end if
wscript.echo "Checking the file " & strCSVFullFile & " in " & strDIR
NoOfCols = Wscript.Arguments(0) ' usually 8
strTemp = "temp.csv"
strmissing = "missingdata.csv"
Set objOutFile = FileSysObj.CreateTextFile(strDIR & strTemp,True)
Set objOutFileM = FileSysObj.CreateTextFile(strDIR & strmissing,True)
Set inputFile = FileSysObj.OpenTextFile(strDIR & strCSVFullFile, ForReading, True)
' Set inputFile as file to be read from
Dim row, column, outline
Dim fields '(7) '8 fields per line
inputFile.ReadAll 'read to end of file
outline = ""
ReDim MyArray(inputFile.Line-2,NoOfCols) 'current line, minus one for header, and minus one for starting at zero
inputFile.close 'close file so that MyArray can be filled with data starting at the top
Set inputFile = FileSysObj.OpenTextFile(strDIR & strCSVFullFile, ForReading, True) 'back at top
strheadLine = inputFile.ReadLine 'skip header , but keep it for the output file
objOutFile.Write(strheadLine & vbCrLf)
anyBadlines = False
badlineflag = False
Do Until inputFile.AtEndOfStream
fullLine = inputFile.Readline
fields = Split(fullLine,",") 'store line in temp array
For column = 0 To NoOfCols-1 'iterate through the fields of the temp array
myArray(row,column) = fields(column) 'store each field in the 2D array with the given coordinates
'Wscript.Echo myArray(row,column)
if myArray(row,0) = " " or myArray(row,1) = " " then
badlineflag = True
'missline = myArray(row,0) & ", " & myArray(row,1) & ", " & myArray(row,2) & ", " & myArray(row,3) & ", " & myArray(row,4) & ", " & myArray(row,5) & ", " & myArray(row,6) & ", " & myArray(row,7)
'Wscript.Echo missline
'Exit For
end if
if column = NoOfCols-1 then
outline = outline & myArray(row,column) & vbCrLf
else
outline = outline & myArray(row,column) & ","
'csvFile = Regex.Replace(csvFile, "(,\s*?"".*?)(,)(\s+.*?""\s*?,)", "$1$3") 'TEST
end if
Next
cntAllLines = cntAllLines + 1
' Wscript.Echo outline
if badlineflag = False then
objOutFile.Write(fullLine & vbCrLf)
else
' write it somewhere else, drop a header in the first time
if anyBadlines = False Then
objOutFileM.Write(strheadLine & vbCrLf)
End if
objOutFileM.Write(outline)
cntBadLines = cntBadLines + 1
badlineflag = False
anyBadlines = True
end if
outline = ""
row = row + 1 'next line
Loop
objOutFile.Close
objOutFileM.Close
inputFile.close
Wscript.Echo "Total lines in the transaction file = " & cntAllLines
Wscript.Echo "Total bad lines in the file = " & cntBadLines
The below line is able to work as it contains 7 commas (8 columns).
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,ABC
The below line will throw an error as a result of more commas than 7 in the script.
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,Redburn, Europe. Limited
If greater than 7 commas in the CSV file line, the aim is to wrap it all greater than 7 into one field.
E.g. how do you replace Redburn, Europe. Limited string with double quotes as it is one name.
For example, in a text file it would appear like below:
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,"Redburn, Europe. Limited"
Is there a way to write a VB or VBA script to do the above and save it as a .csv file (which is opened via notepad to check the double quotes)?
Option Explicit
Option Compare Text
Public Sub ConvertFile()
Dim lngRowNumber As Long
Dim strLineFromFile As String
Dim strSourceFile As String
Dim strDestinationFile As String
strSourceFile = "U:\Book3.csv"
strDestinationFile = "U:\Book4.csv"
Open strSourceFile For Input As #1
Open strDestinationFile For Output As #2
lngRowNumber = 0
Do Until EOF(1)
Line Input #1, strLineFromFile
strLineFromFile = Right(Replace(strLineFromFile, ",", " ", 1), 1000)
Write #2, strLineFromFile
strLineFromFile = vbNullString
Loop
Close #1
Close #2
End Sub
As I see, you use MS Access (due to Option Compare Text line), so there is better built-in instruments for this task.
Use DoCmd.TransferText for it.
1st step is to create output specification via:
Here you can setup delimiters, even that differs from ", and handle other options.
After that you can use your set-up specification via following command
DoCmd.TransferText acExportDelim, "TblCustomers_export_spec", "TblCustomers", "C:\test\1.txt", True
In this case all characters escaping would be done through built-in instruments. It seems to be more easier to correct this code further.
As mentioned, there is VBScript workaround. For given input data, following function will do desired actions for given string:
Option Explicit
Function funAddLastQuotes( _
strInput _
)
Dim arrInput
arrInput = Split(strInput, ",")
Dim intArrSize
intArrSize = UBound(arrInput)
Dim intCurrentElement
Dim strOutput
Dim intPreLastElement
intPreLastElement = 6
For intCurrentElement = 1 To intPreLastElement
strOutput = strOutput & "," & arrInput(intCurrentElement)
Next
Dim strOutputLastField
For intCurrentElement = intPreLastElement + 1 To intArrSize
strOutputLastField = strOutputLastField & "," & arrInput(intCurrentElement)
Next
strOutputLastField = Right(strOutputLastField, Len(strOutputLastField) - 1)
strOutput = Right(strOutput, Len(strOutput) - 1)
strOutput = strOutput & "," & """" & strOutputLastField & """"
funAddLastQuotes = strOutput
End Function
MsgBox funAddLastQuotes("RXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,Redburn, Europe,,, Limited")
Finally, here is working VBScript solution.
Option Explicit
Const ColumnsBeforeCommadColumn = 6
Function funAddLastQuotes( _
strInput _
)
Dim arrInput
arrInput = Split(strInput, ",")
Dim intArrSize
intArrSize = UBound(arrInput)
Dim intCurrentElement
Dim strOutput
Dim intPreLastElement
intPreLastElement = ColumnsBeforeCommadColumn
For intCurrentElement = 1 To intPreLastElement
strOutput = strOutput & "," & arrInput(intCurrentElement)
Next
Dim strOutputLastField
If (intPreLastElement + 1) < intArrSize _
Then
For intCurrentElement = intPreLastElement + 1 To intArrSize
strOutputLastField = strOutputLastField & "," & arrInput(intCurrentElement)
Next
Else
strOutputLastField = strOutputLastField & "," & arrInput(intArrSize)
End If
strOutputLastField = Right(strOutputLastField, Len(strOutputLastField) - 1)
strOutput = Right(strOutput, Len(strOutput) - 1)
strOutput = strOutput & "," & """" & strOutputLastField & """"
funAddLastQuotes = strOutput
End Function
Public Sub ConvertFile( _
strSourceFile _
)
Dim objFS
Dim strFile
Dim strTemp
Dim ts
Dim objOutFile
Dim objFile
Set objFS = CreateObject("Scripting.FileSystemObject")
Dim strLine
Dim strOutput
Dim strRow
strFile = strSourceFile
strTemp = strSourceFile & ".tmp"
Set objFile = objFS.GetFile(strFile)
Set objOutFile = objFS.CreateTextFile(strTemp,True)
Set ts = objFile.OpenAsTextStream(1,-2)
Do Until ts.AtEndOfStream
strLine = ts.ReadLine
objOutFile.WriteLine funAddLastQuotes(strLine)
Loop
objOutFile.Close
ts.Close
objFS.DeleteFile(strFile)
objFS.MoveFile strTemp,strFile
End Sub
ConvertFile "C:\!accsoft\_in.csv"
You should change following part: ConvertFile "C:\!accsoft\_in.csv as path to your file.
And ColumnsBeforeCommadColumn = 6 is the setting, at which column the chaos with commas begins
I am trying to copy an Excel range to a .txt file.
The export is successful, with one exception, It adds one "extra" empty line at the end.
I've read and tests many of the solution on SO (and other sites), but still without any success.
My Code (relevant part)
' === Export to the .txt file ===
Dim TxtFileName As String, lineText As String
TxtFileName = ThisWorkbook.Path & "\Inv_" & Format(Date, "yyyymmdd") & ".txt"
Open TxtFileName For Output As #1
With StockSht
For i = 1 To LastRow
For j = 1 To 3
If j = 3 Then
lineText = lineText & .Cells(i, j).Value2
Else ' j = 1 or 2
lineText = lineText & .Cells(i, j).Value2 & vbTab
End If
Next j
Print #1, lineText
lineText = ""
Next i
End With
Close #1
My StockSht (worksheet object) and LastRow are defined correctly, and getting their values.
Screen-shot of the end of the exported .txt file
You can use a semi-colon in the Print statement to control the insertion point (i.e. prevent the line-feed on the last line).
The relevant bit on the MSDN page:
Use a semicolon to position the insertion point immediately after the last character displayed.
I tested this code:
Sub PrintTest()
Dim lng As Long
Open "C:\foo3.txt" For Output As #1
For lng = 1 To 10
If lng < 10 Then
Print #1, "foo" & lng
Else
Print #1, "foo" & lng; '<-- semi-colon prevents the newline
End If
Next lng
Close #1
End Sub
So I would update your code like below (not tested):
' === Export to the .txt file ===
Dim TxtFileName As String, lineText As String
TxtFileName = ThisWorkbook.Path & "\Inv_" & Format(Date, "yyyymmdd") & ".txt"
Open TxtFileName For Output As #1
With StockSht
For i = 1 To LastRow
For j = 1 To 3
If j = 3 Then
lineText = lineText & .Cells(i, j).Value2
Else ' j = 1 or 2
lineText = lineText & .Cells(i, j).Value2 & vbTab
End If
Next j
'--- new bit: check for i against LastRow and add the semicolon on last row
If i <> LastRow Then
Print #1, lineText
Else
Print #1, lineText; '<-- semi colon keeps insertion point at end of line
End If
lineText = ""
Next i
End With
Close #1
Try using a ; on the last print line.
' === Export to the .txt file ===
Dim TxtFileName As String, lineText As String
TxtFileName = ThisWorkbook.Path & "\Inv_" & Format(Date, "yyyymmdd") & ".txt"
Open TxtFileName For Output As #1
With StockSht
For i = 1 To LastRow
For j = 1 To 3
If j = 3 Then
lineText = lineText & .Cells(i, j).Value2
Else ' j = 1 or 2
lineText = lineText & .Cells(i, j).Value2 & vbTab
End If
Next j
If i = LastRow Then
Print #1, lineText;
Else
Print #1, lineText
End if
lineText = ""
Next i
End With
Close #1
I will be quick.
I have a variable 'strLine' with text:
The exact string will look like that:
"Text1","Text2","Text3","Text4","Text5"
So, delimiter in my case is: "
How I can extract text and write it in columns.
Expecting results in cells:
A1=Text1
B1=Text2
C1=Text3
D1=Text4
E1=Text5
Thanks
Use Split function, it'll return a 0-based array (ergo +1 in cells) :
Sub test_Andy()
Dim StrLine As String
Dim Str() As String
StrLine = Range("A2").Value 'If your value is in A2
'If you input the value manually, not really practical with so much "
StrLine = Chr(34) & "Text1" & Chr(34) & "," & Chr(34) & "Text2" & Chr(34) & "," & Chr(34) & "Text3" & Chr(34) & "," & Chr(34) & "Text4" & Chr(34) & "," & Chr(34) & "Text5" & Chr(34)
Debug.Print StrLine '"Text1","Text2","Text3","Text4","Text5"
Str = Split(StrLine, ",")
Dim i As Integer
For i = LBound(Str) To UBound(Str)
Cells(1, i + 1) = Str(i)
Cells(2, i + 1) = Replace(Str(i), Chr(34), vbNullString)
Next i
End Sub
You can use Split to split the text into an array, then remove the " from the start and the end of the parts using Mid :
strText = """Text1"",""Text2"",""Text3"",""Text4"",""Text5"""
aSplit = Split(strText, ",")
For Each strCurrent in aSplit
MsgBox Mid(strCurrent, 2, Len(strCurrent) - 2)
Next
Remark : You might want to add some checks to ensure that there is a " at the start and end before removing them.
edited to simulate a StrLine loop:
Dim iRow As Long
irow = 1
For Each StrLine In StrLines '<--' assuming a loop through many StrLines
Str = Split(Replace(StrLine, """", ""), ",")
Cells(iRow, 1).Resize(, UBound(Str) - LBound(Str)).Value = Str
iRow = iRow + 1
Next
I have a csv file, and I need a VBA function that adds quotes to every string value in the file, so that something like
vertical,device_name,value
mobile,Apple iPad,0
mobile,HTC,3
looks like
"vertical","device_name","value"
"mobile","Apple iPad",0
"mobile","HTC",3
What I have found until now is a macro,
Sub QuotesAroundText()
Dim c As Range
For Each c In Selection
If Not IsNumeric(c.Value) Then
c.Value = """" & c.Value & """"
End If
Next c
End Sub
that does almost exactly what I need - it add the quotes, but not to string, but to excel cells. That means, that this macro does work correctly in a xlsx file, but not in a csv file.
So I need a vba code that adds quotes not to cells, but to string, that are between commas.
By emulating a string builder I was able to process a CSV file with 59,507 Rows x 9 Columns in just over 3 seconds. This process is much faster that standard concatenation.
This function was modified from my answer to Turn Excel range into VBA string
Test
Sub TestProcessCSVFile()
Dim s As String
Dim Start: Start = Timer
ProcessCSVFile "C:\Users\Owner\Downloads\SampleCSVFile_53000kb.csv", "C:\Users\Owner\Downloads\_temp.csv"
Debug.Print "Execution Time: "; Timer - Start; "Second(s)"
End Sub
Code
Sub ProcessCSVFile(OldFile As String, NewFile As String)
Dim Data As String, text As String
Dim vCell
Dim length As Long
Open OldFile For Binary As #1
Data = Space$(LOF(1))
Get #1, , Data
Close #1
text = Space(Len(Data) * 1.5)
For Each vCell In Split(Replace(Data, vbCrLf, "," & vbCrLf & ","), ",")
If Len(vCell) + length + 5 > Len(text) Then text = text & Space(Len(Data) * 0.1)
If vCell = vbCrLf Then
Mid(text, length, 1) = vbCrLf
ElseIf IsNumeric(vCell) Then
Mid(text, length + 1, Len(vCell) + 1) = vCell & ","
length = length + Len(vCell) + 1
Else
Mid(text, length + 1, Len(vCell) + 3) = Chr(34) & vCell & Chr(34) & ","
length = length + Len(vCell) + 3
End If
Next
Open NewFile For Output As #1
Print #1, Left(text, length - 1)
Close #1
End Sub
Results
Read the text file in using line input, then taylor the following process to your needs:
Sub y()
a = "a,b,c,d"
'Split into 1d Array
b = Split(a, ",", , vbTextCompare)
'for each element in array add the quotes
For c = 0 To UBound(b)
b(c) = """" & b(c) & """"
Next c
'join the product up
d = Join(b, ",")
'Print her out
Debug.Print d
End Sub
use workbooks.opentext filename:="your csv file with path",
It will open the csv and separate them into cells,
then apply your macro and save again as csv
I have a folder with thousands of files, and a spreadsheet that has 2 pieces of information:
DocumentNumber Revision
00-STD-GE-1234-56 3
I need to find and concatenate all files in the folder than match this document number and revision combination into this format:
00-STD-GE-1234-56_3.docx|00-STD-GE-1234-56_3.pdf
The pdf must be last
sometimes the file is named without the last 3 chars of the document number (if they are -00 they are left off)
sometimes the revision is separated using "_" and sometimes using "_r"
I have the code working, but it takes a long time (this sheet has over 7000 rows, and this code is 20 file comparisons per row against a network file system), is there an optimization for this?
''=============================================================================
Enum IsFileOpenStatus
ExistsAndClosedOrReadOnly = 0
ExistsAndOpenSoBlocked = 1
NotExists = 2
End Enum
''=============================================================================
Function IsFileReadOnlyOpen(FileName As String) As IsFileOpenStatus
'ExistsAndClosedOrReadOnly = 0
'ExistsAndOpenSoBlocked = 1
'NotExists = 2
With New FileSystemObject
If Not .FileExists(FileName) Then
IsFileReadOnlyOpen = 2 ' NotExists = 2
Exit Function 'Or not - I don't know if you want to create the file or exit in that case.
End If
End With
Dim iFilenum As Long
Dim iErr As Long
On Error Resume Next
iFilenum = FreeFile()
Open FileName For Input Lock Read As #iFilenum
Close iFilenum
iErr = Err
On Error GoTo 0
Select Case iErr
Case 0: IsFileReadOnlyOpen = 0 'ExistsAndClosedOrReadOnly = 0
Case 70: IsFileReadOnlyOpen = 1 'ExistsAndOpenSoBlocked = 1
Case Else: IsFileReadOnlyOpen = 1 'Error iErr
End Select
End Function 'IsFileReadOnlyOpen
''=============================================================================
Function BuildAndCheckPath(sMasterPath As String, sLegacyDocNum As String, sRevision As String) As String
Dim sLegacyDocNumNoSheet As String
sLegacyDocNumNoSheet = Left(sLegacyDocNum, Len(sLegacyDocNum) - 3)
Dim sFileExtensions
sFileExtensions = Array(".doc", ".docx", ".xls", ".xlsx", ".pdf")
Dim sRevisionSpacer
sRevisionSpacer = Array("_", "_r")
Dim i As Long
Dim j As Long
Dim sResult As String
'for each revision spacer option
For i = LBound(sRevisionSpacer) To UBound(sRevisionSpacer)
'for each file extension
For j = LBound(sFileExtensions) To UBound(sFileExtensions)
'Check if the file exists (assume a sheet number i.e. 00-STD-GE-1234-56)
If IsFileReadOnlyOpen(sMasterPath & sLegacyDocNum & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
If sResult = "" Then
sResult = sLegacyDocNum & sRevisionSpacer(i) & sRevision & sFileExtensions(j)
Else
sResult = sResult & "|" & sLegacyDocNum & sRevisionSpacer(i) & sRevision & sFileExtensions(j)
End If
End If
'Do it again without a sheet number in the filename (last 3 digits stripped off legacy number)
If IsFileReadOnlyOpen(sMasterPath & sLegacyDocNumNoSheet & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
If sResult = "" Then
sResult = sLegacyDocNumNoSheet & sRevisionSpacer(i) & sRevision & sFileExtensions(j)
Else
sResult = sResult & "|" & sLegacyDocNumNoSheet & sRevisionSpacer(i) & sRevision & sFileExtensions(j)
End If
End If
Next j
Next i
BuildAndCheckPath = sResult
End Function
It's hard to tell without seeing your dataset, but perhaps this approach could be implemented (note the use of Wildcards):
UNTESTED
Const Folder As String = "C:\YourFolder\"
Dim File as Object
Dim XLSFile As String
Dim PDFFile As String
Dim ConCat() As String
Dim DocNos() As Variant
Dim DocRev() As Variant
Dim i As Long
DocNos = Range("A1:A10") '<--Your list of Document #s.
DocRev = Range("B1:B10") '<--Your list of Revision #s.
ReDim ConCat(1 To UBound(DocNos))
'Loop through your Document numbers.
For i = LBound(DocNos) To UBound(DocNos)
'Loop through the folder.
File = Dir(Folder)
Do While File <> ""
'Check the filename against the Document number. Use a wildcard at this _
'point as a sort of "gatekeeper"
If File Like Left(DocNos(i), Len(DocNos(i)) - 3) & "*"
'If the code makes it to this point, you just need to match file _
'type and revision.
If File Like "*_*" & DocRev(i) And File Like "*.xls*" Then
XLSFile = File
ElseIf File Like "*_*" & DocRev(i) File Like "*.pdf" Then
PDFFile = File
End If
If XLSFile <> "" And PDFFile <> "" Then
ConCat(i) = XLSFile & "|" & PDFFile
XLSFile = vbNullString
PDFFile = vbNullString
End If
End If
File = Dir
Loop
Next i
To print the results to your sheet (Transpose pastes the results of the array in one column instead of putting the results in one row), you could use something like this:
Dim Rng As Range
Set Rng = Range("C1")
Rng.Resize(UBound(ConCat),1).Value = Application.Transpose(ConCat)
This approach loops through each document number from your spreadsheet, and then checks each file in the folder to see if it matches the document number, document type, and revision number. Once it finds a match for both .xls* and .pdf types, it concatenates the filenames together.
See this great SO post regarding looping through files.
See this site for more info about the Dir function.
See this article regarding wilcard character usage when comparing strings.
Hope that helps!
Seems to me you are doing unnecessary file existence checks even in cases where a file has already been found. Assuming that talking with your network drive is indeed what takes up most of your execution time, then there's a place to optimise.
What you're doing is this:
If IsFileReadOnlyOpen(sMasterPath & sLegacyDocNum & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
'Great. Found it.
'...
End If
'Do it again without a sheet number in the filename (last 3 digits stripped off legacy number)
'Wait a minute... why ask me to look again if I already found it?
'He must not mind the extra waiting time... ok, here we go again.
If IsFileReadOnlyOpen(sMasterPath & sLegacyDocNumNoSheet & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
'...
End If
I think you want to look for your file under a different filename if and only if you haven't found it under the first filename pattern. Can do this using an Else clause:
If IsFileReadOnlyOpen(sMasterPath & sLegacyDocNum & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
'Great. Found it.
Else
'Didn't find it using the first filename format.
'Do it again without a sheet number in the filename (last 3 digits stripped off legacy number)
If IsFileReadOnlyOpen(sMasterPath & sLegacyDocNumNoSheet & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
'Great. Found it.
Else
Err.Raise 53, , _
"File not found even though I looked for it in two places!"
End If
End If
This can theoretically cut your number of tries by up to half; likely less in practice, but you'll get the largest benefit if you check the most common filename pattern first. The benefit will be proportionally larger if you have a greater number of filename patterns; from your question I understand you have 4 different combinations?
If you have more than 2 patterns to check, then nesting a bunch of Else clauses will look silly and be difficult to read; instead you can do something like this:
Dim foundIt As Boolean
foundIt = False
If Not foundIt And IsFileReadOnlyOpen(sMasterPath & sLegacyDocNum & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
'Great. Found it.
foundIt = True
End If
If Not foundIt And IsFileReadOnlyOpen(sMasterPath & sLegacyDocNumNoSheet & sRevisionSpacer(i) & sRevision & sFileExtensions(j)) <> 2 Then
'Great. Found it.
foundIt = True
End If
'...
'... check your other patterns here...
'...
If Not foundIt Then
Err.Raise 53, , _
"File not found even though I looked for it various places!"
End If