VB6 String variable substr - vb6

Sub guessLetter(letterGuess As String)
Dim lengthOfSecretWord As Integer
lengthOfSecretWord = Len(Secret_word) - 1
tempWord = ""
Dim letterPosition As Integer
For letterPosition = 0 To lengthOfSecretWord
If Mid(Secret_word, letterPosition, 1) = letterGuess Then
tempWord = tempWord & letterGuess
Else
tempWord = tempWord & Mid(lblTempWord, letterPosition, 1)
End If
Next
lblTempWord = tempWord
End Sub
I have runtime error "5" and the problem in line IF, i'm stuck to declare Secret_word.substr(letterPosition, 1) on vb6, first i try write Secret_word.substr(letterPosition, 1) but it can't then i try to manipulate that then runtime error 5 came

The Mid Function in VB (like most things in VB) is 1-indexed, not 0-indexed.
I'm assuming you're familiar with other languages in which you would loop from 0 to Len(String)-1, but VB thinks you'll find it more intuitive to loop from 1 to Len(String).
Refer to the description and example in the documentation for more details.

Related

Symbol already defined differently VB

I'm trying to compile the following code, and I keep getting an error. I got this erro before multiple times so I was forced to use workaround functions. This time I'm really tired of this issue and I need to know what's wrong here.
sub SQL_AddTestResults (byval sData as string, byval testID as integer)
dim i as integer
dim dataChain as string
dim aData (Split(sData, ";").length) as string
aData = Split(sData, ";")
for i = 0 to aData.Length
if(i = 4) then
goto skip
elseif (i = 68) then
goto skip
elseif (i = 72) then
goto skip
end if
if(i = aData.length) then
dataChain = dataChain & aData(i)
else
dataChain = dataChain & aData(i) & ", "
end if
skip:
next
MsgBox (dataChain)
SQL_statement = "INSERT INTO ""TestData"" VALUES (" & dataChain & ");"
Stmt = connection.createStatement()
Stmt.executeUpdate(SQL_statement)
end sub
Compiling this code gives me the following error on "for i = 0 to aData.Length" line:
Basic syntax error.
Symbol aData already defined differently.
Have no idea why. Apologies if that's a trivial problem, but I'm completely new to VB. C++ didn't prepare me for this.
Arrays in classic VB don't have a "length" property. I'm not sure where you got that from.
The way to get the bounds of an array in classic VB is with the LBound and UBound functions.
for i = LBound(aData) to UBound(aData)
This way you can even handle arrays that don't have 0 as the starting index, as yes, one of VB's wonderful quirks is that it lets you use any range of numbers for your indexes.
VB6 isn't a language I'd recommend for new development. If you're trying to learn something new, there are plenty of other options. As you've no doubt noticed, it's harder and harder to find documentation on how classic VB does things, and how it differs from VBScript and VB.NET. If you need to be maintaining an older VB6 code base, I'd recommend finding a used book somewhere that goes over VB6 syntax and usage.
Try this code corrected code:
sub SQL_AddTestResults (byval sData as string, byval testID as integer)
dim i as integer
dim dataChain as string
dim aData as variant
aData = Split(sData, ";")
for i = 0 to ubound(aData)
if(i = 4) then
goto skip
elseif (i = 68) then
goto skip
elseif (i = 72) then
goto skip
end if
if(i = ubound(aData)) then
dataChain = dataChain & aData(i)
else
dataChain = dataChain & aData(i) & ", "
end if
skip:
next
MsgBox (dataChain)
SQL_statement = "INSERT INTO ""TestData"" VALUES (" & dataChain & ");"
Stmt = connection.createStatement()
Stmt.executeUpdate(SQL_statement)
end sub
What I could gather, you are defining aData twice but in different ways -
dim aData (Split(sData, ";").length) as string
aData = Split(sData, ";")
aData length will return an integer of the actual length whilst you are asking it to return a string, and you are using it in your integer loop for i as counter.
Immediately after that you are telling it to return just some data causing the crash. Rather use another nominator to hold the two different kinds of returned information you need -
dim aData (Split(sData, ";").length) as Long ''Rather use long as the length might exceed the integer type. Use the same for i, change integer to long
Dim bData = Split(sData, ";") as String
for i = 0 to aData.Length
if(i = 4) then
goto skip
elseif (i = 68) then
goto skip
elseif (i = 72) then
goto skip
end if
if(i = aData.length) then
dataChain = dataChain & bData(i)
else
dataChain = dataChain & bData(i) & ", "
end if
skip:
next

array.slice(start, end) in vbscript?

Anyone have a favorite implementation of the standard (e.g. jscript, javascript) array.slice(start,end) function in vbscript?
It seems to be commonly missed (among vbscript programmers anyway) and sharing a good implementation would help. If one doesn't show up, I guess I'll have to answer my own question and write something.
For completeness, this might be a better version:
Function Slice (aInput, Byval aStart, Byval aEnd)
If IsArray(aInput) Then
Dim i
Dim intStep
Dim arrReturn
If aStart < 0 Then
aStart = aStart + Ubound(aInput) + 1
End If
If aEnd < 0 Then
aEnd = aEnd + Ubound(aInput) + 1
End If
Redim arrReturn(Abs(aStart - aEnd))
If aStart > aEnd Then
intStep = -1
Else
intStep = 1
End If
For i = aStart To aEnd Step intStep
If Isobject(aInput(i)) Then
Set arrReturn(Abs(i-aStart)) = aInput(i)
Else
arrReturn(Abs(i-aStart)) = aInput(i)
End If
Next
Slice = arrReturn
Else
Slice = Null
End If
End Function
This avoids a number of issues with the previous answer:
No consideration of objects in the array
Negative start and end values are allowed; they count backwards from the end
If start is higher than end gives a reversed array subset
The (expensive) redim preserve is not necessary since the array is empty
A defined result is returned (Null) if the input is not an array
Uses the built-in function IsArray instead of string manipulation/comparison on the input
This is one I've used in the past:
Function Slice(arr, starting, ending)
Dim out_array
If Right(TypeName(arr), 2) = "()" Then
out_array = Array()
ReDim Preserve out_array(ending - starting)
For index = starting To ending
out_array(index - starting) = arr(index)
Next
Else
Exit Function
End If
Slice = out_array
End Function
Function Slice(arr, starting, ending)
Dim out_array
If Right(TypeName(arr), 2) = "()" Then
out_array = Array()
If ending=UBound(arr)+1 Then
actending=ending-1
ReDim Preserve out_array(actending - starting)
For index = starting To actending
out_array(index - starting) = arr(index)
Next
Else
ReDim Preserve out_array(ending - starting)
For index = starting To ending
out_array(index - starting) = arr(index)
Next
End If
Else
Exit Function
End If
Slice = out_array
End Function

(VB6) Slicing a string before a certain point

Suppose I have a variable set to the path of an image.
Let img = "C:\Users\Example\Desktop\Test\Stuff\Icons\test.jpg"
I want to slice everything before "\Icons" using Vb6. So after slicing the string it would be "\Icons\test.jpg" only.
I have tried fiddling with the Mid$ function in VB6, but I haven't really had much success. I am aware of the fact that Substring isn't a function available in vb6, but in vb.net only.
After the first \icons
path = "C:\Users\Example\Desktop\Test\Stuff\Icons\test.jpg"
?mid$(path, instr(1, path, "\icons\", vbTextCompare))
> \Icons\test.jpg
Or after the last should there be > 1
path = "C:\Users\Example\Desktop\Test\Icons\Stuff\Icons\test.jpg"
?right$(path, len(path) - InStrRev(path, "\icons\", -1, vbTextCompare) + 1)
> \Icons\test.jpg
This is pretty easy to do generically using the Split function. I wrote a method to demonstrate it's use and for grins it takes an optional parameter to specify how many directories you want returned. Passing no number returns a file name, passing a very high number returns a full path (either local or UNC). Please note there is no error handling in the method.
Private Function GetFileAndBasePath(ByVal vPath As String, Optional ByVal baseFolderLevel = 0) As String
Dim strPathParts() As String
Dim strReturn As String
Dim i As Integer
strPathParts = Split(vPath, "\")
Do While i <= baseFolderLevel And i <= UBound(strPathParts)
If i > 0 Then
strReturn = strPathParts(UBound(strPathParts) - i) & "\" & strReturn
Else
strReturn = strPathParts(UBound(strPathParts))
End If
i = i + 1
Loop
GetFileAndBasePath = strReturn
End Function

Excel copy/sort data while counting/removing duplicates

Ok so I've searched and searched and can't quite find what I'm looking for.
I have a workbook and what I'm basically trying to do is take the entries from certain ranges (Sheet1 - E4:E12, E14:E20, I4:I7, I9:I12, I14:I17, & I19:I21) and put them in a separate list on Sheet2. I then want the new list on Sheet2 to be sorted by how many times an entry appeared on Sheet1 as well as display the amount.
example http://demonik.doomdns.com/images/excel.png
Obviously as can be seen by the ranges I listed above, this sample is much smaller lol, was just having trouble trying to figure out how to describe everything and figured an image would help.
Basically I am trying to use VBA (the update would be initialized by hitting a button) to copy data from Sheet1 and put all the ranges into one list in Sheet2 that is sorted by how many times it appeared on Sheet1, and then alphabetically.
If a better discription is needed just comment and let me know, I've always been horrible at trying to describe stuff like this lol.
Thanks in advance!
Another detail: I cant have it search for specific things as the data in the ranges on Sheet1 may change. Everything must be dynamic.
I started out with this data
and used the following code to read it into an array, sort the array, and count the duplicate values, then output the result to sheet2
Sub Example()
Dim vCell As Range
Dim vRng() As Variant
Dim i As Integer
ReDim vRng(0 To 0) As Variant
Sheets("Sheet2").Cells.Delete
Sheets("Sheet1").Select
For Each vCell In ActiveSheet.UsedRange
If vCell.Value <> "" Then
ReDim Preserve vRng(0 To i) As Variant
vRng(i) = vCell.Value
i = i + 1
End If
Next
vRng = CountDuplicates(vRng)
Sheets("Sheet2").Select
Range(Cells(1, 1), Cells(UBound(vRng), UBound(vRng, 2))) = vRng
Rows(1).Insert
Range("A1:B1") = Array("Entry", "Times Entered")
ActiveSheet.UsedRange.Sort Range("B1"), xlDescending
End Sub
Function CountDuplicates(List() As Variant) As Variant()
Dim CurVal As String
Dim NxtVal As String
Dim DupCnt As Integer
Dim Result() As Variant
Dim i As Integer
Dim x As Integer
ReDim Result(1 To 2, 0 To 0) As Variant
List = SortAZ(List)
For i = 0 To UBound(List)
CurVal = List(i)
If i = UBound(List) Then
NxtVal = ""
Else
NxtVal = List(i + 1)
End If
If CurVal = NxtVal Then
DupCnt = DupCnt + 1
Else
DupCnt = DupCnt + 1
ReDim Preserve Result(1 To 2, 0 To x) As Variant
Result(1, x) = CurVal
Result(2, x) = DupCnt
x = x + 1
DupCnt = 0
End If
Next
Result = WorksheetFunction.Transpose(Result)
CountDuplicates = Result
End Function
Function SortAZ(MyArray() As Variant) As Variant()
Dim First As Integer
Dim Last As Integer
Dim i As Integer
Dim x As Integer
Dim Temp As String
First = LBound(MyArray)
Last = UBound(MyArray)
For i = First To Last - 1
For x = i + 1 To Last
If MyArray(i) > MyArray(x) Then
Temp = MyArray(x)
MyArray(x) = MyArray(i)
MyArray(i) = Temp
End If
Next
Next
SortAZ = MyArray
End Function
End Result:
Here is a possible solution that I have started for you. What you are asking to be done gets rather complicated. Here is what I have so far:
Option Explicit
Sub test()
Dim items() As String
Dim itemCount() As String
Dim currCell As Range
Dim currString As String
Dim inArr As Boolean
Dim arrLength As Integer
Dim iterator As Integer
Dim x As Integer
Dim fullRange As Range
Set fullRange = Range("E1:E15")
iterator = 0
For Each cell In fullRange 'cycle through the range that has the values
inArr = False
For Each currString In items 'cycle through all values in array, if
'values is found in array, then inArr is set to true
If currCell.Value = currString Then 'if the value in the cell we
'are currently checking is in the array, then set inArr to true
inArr = True
End If
Next
If inArr = False Then 'if we did not find the value in the array
arrLength = arrLength + 1
ReDim Preserve items(arrLength) 'resize the array to fit the new values
items(iterator) = currCell.Value 'add the value to the array
iterator = iterator + 1
End If
Next
'This where it gets tricky. Now that you have all unique values in the array,
'you will need to count how many times each value is in the range.
'You can either make another array to hold those values or you can
'put those counts on the sheet somewhere to store them and access them later.
'This is tough stuff! It is not easy what you need to be done.
For x = 1 To UBound(items)
Next
End Sub
All that this does so far is get unique values into the array so that you can count how many times each one is in the range.

How to reduce the decimal length

I want to reduce the decimal length
text1.text = 2137.2198231578
From the above, i want to show only first 2 digit decimal number
Expected Output
text1.text = 2137.21
How to do this.
Format("2137.2198231578", "####.##")
I was about to post use Format() when I noticed p0rter comment.
Format(text1.text, "000.00")
I guess Int() will round down for you.
Been many years since I used VB6...
This function should do what you want (inline comments should explain what is happening):
Private Function FormatDecimals(ByVal Number As Double, ByVal DecimalPlaces As Integer) As String
Dim NumberString As String
Dim DecimalLocation As Integer
Dim i As Integer
Dim LeftHandSide As String
Dim RightHandSide As String
'convert the number to a string
NumberString = CStr(Number)
'find the decimal point
DecimalLocation = InStr(1, NumberString, ".")
'check to see if the decimal point was found
If DecimalLocation = 0 Then
'return the number if no decimal places required
If DecimalPlaces = 0 Then
FormatDecimals = NumberString
Exit Function
End If
'not a floating point number so add on the required number of zeros
NumberString = NumberString & "."
For i = 0 To DecimalPlaces
NumberString = NumberString & "0"
Next
FormatDecimals = NumberString
Exit Function
Else
'decimal point found
'split out the string based on the location of the decimal point
LeftHandSide = Mid(NumberString, 1, DecimalLocation - 1)
RightHandSide = Mid(NumberString, DecimalLocation + 1)
'if we don't want any decimal places just return the left hand side
If DecimalPlaces = 0 Then
FormatDecimals = LeftHandSide
Exit Function
End If
'make sure the right hand side if the required length
Do Until Len(RightHandSide) >= DecimalPlaces
RightHandSide = RightHandSide & "0"
Loop
'strip off any extra didgits that we dont want
RightHandSide = Left(RightHandSide, DecimalPlaces)
'return the new value
FormatDecimals = LeftHandSide & "." & RightHandSide
Exit Function
End If
End Function
Usage:
Debug.Print FormatDecimals(2137.2198231578, 2) 'outputs 2137.21
Looks fairly simple, but I must be missing something subtle here. What about:
Option Explicit
Private Function Fmt2Places(ByVal Value As Double) As String
Fmt2Places = Format$(Fix(Value * 100#) / 100#, "0.00")
End Function
Private Sub Form_Load()
Text1.Text = Fmt2Places(2137.2198231578)
End Sub
This also works in locales where the decimal point character is a comma.

Resources