False positives and False Negatives with Instr function - arrays

I am trying to look through an array for values using InStr. However, I am getting false positives and false negatives.
I.e. there will be a string match and no match will be reported or no match reported even though the string matches exactly.
It requires Outlook. It converts the highlighted emails into a text file placed in the specified path. It then searches the text file for the delimeter by reading the text into an array and searching the array contents. However, as mentioned, even when the substring is in the array, InStr returns false positives and false negatives. I have tried binary and textual comparison methods and various comparison strings.
Any ideas?
Notes: 1)after becoming frustrated with InStr, I attempted to use an if then statement to compare the array to the delimeter string, which is what is shown in the last lines of my code.
2)i have set the delimeter as "xxxxx" which you can see in the lines following the set of objfile.write commands.
3)I have tried to use both text and binary comparison modes with the instr function
3) Ultimate goal:
a)Extract highlighted emails from outlook and combine into one text file.
b)Sort the delimited text file based on the text of the email (if text between delimiters contains y, put into array y, if x...etc.)
c)print arrays into email in my specified order (e.g. x, y, z)
this is because the emails arrive at different times each day, but must be organized into the same order each day for the final summary email.
Thanks.
Below is my code:
Sub MergeTextFromSelectedEmailsIntoTextFile()
Dim objFS As New Scripting.FileSystemObject, objFile As Scripting.TextStream
Dim objItem As Object, strFile As String
Dim wrapArray() As String
If ActiveExplorer.Selection.Count = 0 Then Exit Sub
strFile = InputBox("Please enter the full path and file name for the merged text:" _
, "Enter File Name")
Set objFile = objFS.CreateTextFile(strFile, False)
If objFile Is Nothing Then
MsgBox "Error creating file '" & strFile & "'.", vbOKOnly + vbExclamation _
, "Invalid File"
Exit Sub
End If
For Each objItem In ActiveExplorer.Selection
objFile.Write vbCr
objFile.Write (vbCr & Chr(10) & Chr(13) & ("xxxxx") & Chr(13) & Chr(13) & vbCr & vbLf)
objFile.Write (vbCr & vbLf & objItem.Body)
objFile.Write (vbCr & vbLf & Chr(13))
Next
objFile.Close
'Define variables for writing to array
Dim i As Integer
Set objFile = objFS.OpenTextFile(strFile, ForReading)
'write file contents to array
Do Until objFile.AtEndOfStream
ReDim Preserve wrapArray(i)
wrapArray(i) = objFile.ReadLine
i = i + 1
Loop
Dim xxxxx As String
xxxxx = xxxxx
'check each array index for contents
'note i have tried
''if instr(0, wraparray(i), "xxxxx",0) then msgBox "FoundDelim at line " & i
For i = LBound(wrapArray()) To UBound(wrapArray())
If wrapArray(i) = "xxxxx" Then MsgBox "FoundDelim! at line " & i
Next i

Note that InStr returns an integer, so testing the result of the function as a boolean should result in inconsistent behavior. Try this:
If InStr(wrapArray(i),"xxxxx") > 0 Then
MsgBox "FoundDelim! at line " & i
End If

Related

Excel VBA find last entry in an array (but not in the spreadsheet)

I have some Excel code that assembles an array of file names, and then loops through and extracts some data from them. The data is not in the spreadsheet itself - it is completely assembled within VBA. New files are added each month, so the number will vary.
My problem is that code that was working is no longer working, and I'm trying to figure out a workaround. (Related: Error: Microsoft Excel has stopped working - But I didn't change anything)
UBound finds the size of the array. But the array is not completely filled with data. How do I find the last item in the array that has something in it?
I am searching and finding answers that relate to finding the number of items on a spreadsheet, but this doesn't really use a worksheet. IT seems like CountA might be what I want, but Excel: Find last value in an array doesn't have an example that I can figure out to make work in my case.
In other words, I'd like to use something besides UBound in the code below, so I don't go past the entries that have something in them.
FName = Array("april2010.xls", "feb2010.xls", "jan2010.xls", "july2010.xls", "june2010.xls", _
"mar2010.xls", "may2010.xls", "sep2010.xls", "..\FINAL-MO-BAL-2011\APRIL2011.xls", _
"..\FINAL-MO-BAL-2011\AUG2011.xls", "..\FINAL-MO-BAL-2011\DEC2011.xls", _
"..\FINAL-MO-BAL-2011\FEB2011.xls", "..\FINAL-MO-BAL-2011\JAN2011.xls", _
"..\FINAL-MO-BAL-2011\JULY2011.xls", "..\FINAL-MO-BAL-2011\JUNE2011.xls", _
"..\FINAL-MO-BAL-2011\MARCH2011.xls", "..\FINAL-MO-BAL-2011\MAY2011.xls", _
"..\FINAL-MO-BAL-2011\NOV2011.xls", "..\FINAL-MO-BAL-2011\OCT2011.xls", _
"..\FINAL-MO-BAL-2011\SEP2011.xls", FName2, FName3, FName4, FName5, FName6, _
FName7, FName8, FName9, FName10, FName11, FName12, FName13, FName14, FName15, _
FName16, FName17, FName18, FName19, FName20, FName21, FName22, FName23, FName24, _
FName25, FName26, FName27, FName28, FName29, FName30, FName31, FName32, FName33, _
FName34, FName35, FName36, FName37, FName38, , FName39, FName40, FName41, FName42, _
FName43, FName44, FName45, FName46, FName47, FName48, FName49)
If IsArray(FName) Then
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
WorkbookName = ThisWorkbook.Name
rnum = 1
For Fnum = LBound(FName) To UBound(FName)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(Filename:=FName(Fnum), ReadOnly:=True)
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
.CutCopyMode = False
.DisplayAlerts = False
.Visible = False
End With
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
Use the Filter function
Dim fName As Variant
Dim fltName As Variant
fName = Array("april2010.xls", "feb2010.xls", "jan2010.xls", "july2010.xls", "june2010.xls", _
"mar2010.xls", "may2010.xls", "sep2010.xls", "..\FINAL-MO-BAL-2011\APRIL2011.xls", _
"..\FINAL-MO-BAL-2011\AUG2011.xls", "..\FINAL-MO-BAL-2011\DEC2011.xls", _
"..\FINAL-MO-BAL-2011\FEB2011.xls", "..\FINAL-MO-BAL-2011\JAN2011.xls", _
"..\FINAL-MO-BAL-2011\JULY2011.xls", "..\FINAL-MO-BAL-2011\JUNE2011.xls", _
"..\FINAL-MO-BAL-2011\MARCH2011.xls", "..\FINAL-MO-BAL-2011\MAY2011.xls", _
"..\FINAL-MO-BAL-2011\NOV2011.xls", "..\FINAL-MO-BAL-2011\OCT2011.xls", _
"..\FINAL-MO-BAL-2011\SEP2011.xls", "FName2", "FName3", "FName4", "FName5", "FName6", _
"FName7", "FName8", "FName9", "FName10", "FName11", "FName12", "FName13", "FName14", "FName15", _
"FName16", "FName17", "FName18", "FName19", "FName20", "FName21", "FName22", "FName23", "FName24", _
"FName25", "FName26", "FName27", "FName28", "FName29", "FName30", "FName31", "FName32", "FName33", _
"FName34", "FName35", "FName36", "FName37", "FName38", "", "FName39", "FName40", "FName41", "FName42", _
"FName43", "FName44", "FName45", "FName46", "FName47", "FName48", "FName49")
fltName = Filter(fName, ".")
Debug.Print LBound(fltName), UBound(fltName)
I'm not sure what FName2, FName3, etc are supposed to be. You said there were array elements with no data, so maybe they are just placeholders to demonstrate.
At any rate, I filtered on a dot so filter out what wasn't a file name. You may want to filter on something different.
You could do something like this right before you start your loop through the FName array:
Dim LastFilled As Integer 'a variable to hold the last location filled in the array
'This is checking the array from the last to first
For i = UBound(FName) To 1 Step -1
If FName(i) Is Not Empty Then
LastFilled = i
Exit For
End If
Next i
Then replace your UBound(FName) with LastFilled
Instead of skipping the error, check that the entry in the array is not empty and that the path exists.
You may also have to change the current directory with ChDir if CurDir doesn't return the expected one.
Something like:
Dim i As long, fname As String
' set the current directory with the directory of this workbook '
ChDir ThisWorkbook.Path
For i = LBound(FNames) To UBound(FNames)
fname = FNames(i)
' if has entry '
If Len(fname) Then
' if file exists '
If Len(Dir(fname)) Then
' open workbook '
Set wb = Workbooks.Open(Filename:=fname, ReadOnly:=True)
End If
End If
Next

Duplicate Entry Warning Message Box

I am trying to have a message box appear when a duplicate number is entered. A duplicate in this table would be if BOTH fields match, [Source] and [Voucher_Number].
[Source] is formatted as text
[Voucher_Number] is formatted as Number
Here is what my code looks like:
If (IsNull(DLookup("Source", "tblInvoiceLog", "Source ='" &
Me.Source.Value & "'"))) And _
(IsNull(DLookup("Voucher_Number", "tblInvoiceLog", "Voucher_Number ='" &
Me.Voucher_Number.Value & "'"))) Then
Else
MsgBox "Duplicate Entery!" & Chr(13) & Chr(10) & "Please Use the Next
Available Consecutive Voucher Number", vbInformation, "Required"
End If
End Sub
I am getting:
Run Time error 3464
What I would ultimately like to do, aside from solve this problem, is in the message box return the value of the field in the [Vendor_Name] for the original entry.
Thank you for any help anyone can lend
You could try casting the DLookup return values specifically as strings to ensure you are comparing apples to apples. If you still get an error, use F8 to step through it and hover over s1stLookup and s2ndLookup to see what values are assigned to the variables.
Dim s1stLookup as String
Dim s2ndLookup as String
'Specifically cast the DLookup return values as Strings
s1stLookup = CStr(DLookup("Source", "tblInvoiceLog", "Source ='" & Me.Source.Value & "'"))
s2ndLookup = CStr(DLookup("Voucher_Number", "tblInvoiceLog", "Voucher_Number ='" & Me.Voucher_Number.Value & "'"))
If (IsNull(s1stLookup)) And (IsNull(s2ndLookup)) Then
'... Presumably some code here
Else
MsgBox "Duplicate Entery!" & vbCrLF & _
"Please Use the Next Available Consecutive Voucher Number", _
vbInformation, "Required"
End If
Currently you are testing for both values separately. But
A duplicate in this table would be if BOTH fields match, [Source] and [Voucher_Number].
So you need to test if both values exist in the same record by putting both conditions with AND into the DLookup call. And since you want to get the [Vendor_Name] if it is a duplicate, you can directly lookup this field:
Dim sVendor as String
sVendor = Nz(DLookup("Vendor_Name", "tblInvoiceLog", _
"Source = '" & Me.Source & "' AND Voucher_Number = " & Me.Voucher_Number), "")
If sVendor <> "" Then
MsgBox "Duplicate entry of vendor '" & sVendor & "'."
Else
' ok, no dupe
End If
I find it's best to always use Nz() with DLookup() so I can work with strings instead of variants. An empty string means there was no result.

Convert Access Attachment data type to file system files

I have a lot of files stored as attached files in an Access db. I am going to move data to an SQL server and for that purpose I need to extract the attached files and turn them into file system files.
This snippet works fine for images and pdf files but not for Office documents like Word or Excel. I assume it has something to do with encoding, but I have no clues. Any ideas?
Dim dbs As Database
Dim rs As Recordset
Set dbs = CurrentDb
Set rs = dbs.OpenRecordset("table1")
With rs
Do While Not .EOF
Set rsRec = rs.Fields("AttFiles").Value
While Not rsRec.EOF
NameOfFile = "C:\temp\" & rsFil.Fields("FileName")
Open NameOfFile For Binary Access Write As #1
Put #1, , rsRec.Fields("FileData").Value
Close #1
rsRec.MoveNext
Wend
.MoveNext
Loop
End With
rs.Close
dbs.Close
If the File is actually an attachment type, then you might as well use the Recordset2 of the Microsoft Access Object Library. Something like,
Public Sub exportDocument(tableName As String, fieldName As String, uniqueID As Long)
On Error GoTo Err_SaveImage
Dim rsParent As DAO.Recordset2
Dim rsChild As DAO.Recordset2
Dim saveAsName As String
Set rsParent = CurrentDb.OpenRecordset("SELECT " & tableName & ".* " & _
"FROM " & tableName & " WHERE " & tableName & "." & fieldName & " = " & uniqueID)
Set rsChild = rsParent.Fields("fileData").Value
If rsChild.RecordCount <> 0 Then
If Dir(Environ("userprofile") & "\My Documents\tmp\", vbDirectory) <> "." Then MkDir Environ("userprofile") & "\My Documents\tmp\"
saveAsName = Environ("userprofile") & "\My Documents\tmp\" & rsChild.Fields("FileName")
rsChild.Fields("fileData").SaveToFile saveAsName
FollowHyperlink saveAsName
End If
Exit_SaveImage:
Set rsChild = Nothing
Set rsParent = Nothing
Exit Sub
Err_SaveImage:
If Err = 3839 Then
Resume Next
Else
MsgBox "Some Other Error occured!" & vbCrLf & vbCrLf & Err.Number & " - " & Err.Description, vbCritical
Resume Exit_SaveImage
End If
End Sub
The above code will save the files to a location specified in saveAsName. I have specific unique ID in the WHERE condition. If you want to export all documents, you can alter the code accordingly, but might have to loop through the recordset. I hope this helps !

Putting all elements of an array variable onto their own line in a message box

The code below is a fragment of a macro I'm writing to alert users that they may not have a sufficient number of compatible installation equipment on an order. n shortfalls (i.e., each instance of an equipment item not having compatible installation equipment are saved in the yankees() array in elements 1 to n. What I want to do is prompt users with a message box stating "Please review your order to ensure you have you sufficient compatible installation equipment- we detected the following shortfalls"
and below that
include all each element of yankees(1 to n) on separate lines in a message box with two options below "This is okay, I'll submit my order now" and "Let me go back,I want to modify my order".
How can I create such a message box?
I have:
MsgBox "Please review your order to ensure you have you sufficient compatible installation equipment- we detected the following concerns" & yankee(1), vbOKCancel
currently but this only includes the first shortfall. How can I include all elements of yankee() and put them on their own line?
This question really boils down to: "How do I put all non-blank elements of an array variable onto their own lines in a message box prompt"?
Do
If rip(qbert) < k(qbert) Then
yankee(jets) = "Your order for" & s(qbert) & " contains " & k(qbert) - rip(qbert) & " too few " & g(qbert)
jets = jets + 1
qbert = qbert + 1
Else
qbert = qbert + 1
End If
Loop Until qbert > echo
You can use the Join function:
Sub Test()
Dim var As Variant
'Populate a dummy vector array from a comma-separated list:
var = Split("Alpha,Beta,Gamma,Delta,Epsilon", ",")
'Display the contents of the array as delimited list, use the Carriage Return to delimit:
MsgBox Join(var, vbCR)
End Sub
The above does not ignore blanks. To ignore blanks, per your specific question, you can iterate over the array and test for blank values. I would do this in a Function:
How do I put all non-blank elements of an array variable onto their own lines in a message box prompt
In your sub, just pass yankees to this function, like:
MsgBox = GetMessageText(yankees)
Here is the function:
Function GetMessageText(var As Variant) As String
'Assumes a vector array
On Error GoTo EarlyExit
Dim sMsg As String
Dim v As Variant
For Each v In var
If Not v = vbNullString Then
sMsg = sMsg & v & vbCr
End If
Next
EarlyExit:
If Err.Number = 0 Then
GetMessageText = sMsg
Else:
GetMessageText = "invalid array"
End If
End Function
Alternate:
Sub tgr()
Dim yankee(1 To 5) As String
Dim strMsg As String
yankee(1) = "Did this"
yankee(3) = "experiment"
yankee(5) = "really work?"
'yankee => ["Did this", , "experiment", , "really work?"] _
the yankee array has two blanks at positions 2 and 4 _
and it also has spaces in some of the element strings
strMsg = Replace(Replace(WorksheetFunction.Trim(Replace(Replace(Join(yankee, "|"), " ", "_"), "|", " ")), " ", vbCrLf), "_", " ")
'strMsg => "Did this _
experiment _
really work?"
'Yes it did, see result
MsgBox strMsg
End Sub

VB6 CSV search visualbasic

I have a .csv file that has 100 rows and 8 columns. Each row looks like something below
0,0,0,0,0,0,0,5
0,1,0,0,1,0,0,6
I need to evaluate each field. If the field = 1 (between rows 1 and 7), I have to write the 8th column value for that row to a text box, if the field = 0 write nothing for that row.
I am very confused on how to evaluate each field.
I use ADO with the Jet-Driver. It's very easy an the result of the import is a ADO.Recordset which you can easily navigate through.
Dim cnCSV As ADODB.Connection
Set cnCSV = New ADODB.Connection
cnCSV.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Chr(34) & lFilePath & Chr(34) & ";Extended Properties=" & Chr(34) & "text;HDR=Yes;FMT=Delimited" & Chr(34) & ";"
cnCSV.Open
Dim p_ImportRst As ADODB.Recordset
Set p_ImportRst = New ADODB.Recordset
lstrSQL = "SELECT * FROM [" & lFileName & "]"
Set p_ImportRst = cnCSV.Execute(lstrSQL)
Here is an approach that should work. Pseudo-code-ish...
dim vData() as variant
dim nHandle as integer
dim sTextLine as string
nHandle = FreeFile
open "c:\filename.csv" for input as nHandle
Do While Not EOF(nHandle)
Line Input #nHandle, sTextLine '// Read line into variable.
' break up the line into multiple pieces
vData = split(sTextLine, ",")
' your criteria here
if vData(0) = 0 then ...
if vData(1) = ...
Loop
Close #nHandle
Use "split"
"Splits a string into separate elements based on a delimiter (such as a comma or space) and stores the resulting elements in a zero-based array"
http://www.vb6.us/tutorials/vb-string-array-functions-split-join-filter
Creates a variable size array. Use lbound and ubound to get the size of that, do for loop and add numbers together.

Resources