Finding Substring of String VB - vb.net

1.The Following Program will get two inputs from user i.e A & B
2. Than Find the sub string from B.
3. Finally Print the result.
While my code is
Dim a As String
Dim b As String
a = InputBox("Enter First String", a)
b = InputBox("Enter 2nd String", b)
Dim i As Integer
Dim j As Integer = 0
Dim k As Integer = 0
Dim substr As Integer = 0
For i = 0 To a.Length - 1
If a(i) = b(j) Then
j += 1
If b(j) = 0 Then
MsgBox("second string is substring of first one")
substr = 1
Exit For
End If
End If
Next i
For i = 0 To b.Length - 1
If b(i) = a(k) Then
k += 1
If a(k) = 0 Then
MsgBox(" first string is substring of second string")
substr = 1
Exit For
End If
End If
Next i
If substr = 0 Then
MsgBox("no substring present")
End If
End Sub
While compiling it gives following debugging errors.
Line Col
Error 1 Operator '=' is not defined for types 'Char' and 'Integer'. 17 24
Error 2 Operator '=' is not defined for types 'Char' and 'Integer'. 27 24

It is because of these lines:
If b(j) = 0 Then
If a(k) = 0 Then
As a(k) and b(j) are both of the Char data type (think of the string as an array of characters) but you are trying to compare them to an int (0).
If you are looking for a substring and you're using VB.NET you could try using the IndexOf method, for a very naive example:
If a.IndexOf(b) > -1 Then
MsgBox("b is a substring of a")
ElseIf b.IndexOf(a) > -1 Then
MsgBox("a is a substring of b")
Else
MsgBox("No substring found")
End
If you are using VBA, you could also use InStr but I think with this the string is 1-indexed instead of 0-indexed (as they are in VB.NET) so your check may look something like:
If InStr(a,b) > 0 Then
MsgBox("b is a substring of a")
ElseIf InStr(b,a) > 0 Then
MsgBox("a is a substring of b")
Else
MsgBox("No substring found")
End

Related

Is there a way to maintain the length of a user entered number, to prevent removal of extra 0's?

I'm creating a Diabetes management algorithm, and I'm trying to find a way for the user's entered time blocks to be maintained at 4 digits
I've been searching on google, but all I have been able to find is how to check the length of a variable, which I already know how to do.
Sub timeBlocks()
Dim file As String = "C:\Users\Connor\Documents\Visual Studio 2017\Projects\meterCodeMaybe\TIMEBLOCKS.txt"
Dim blockNum As Integer
Console.WriteLine("Please be sure to enter times as a 24 hour value, rather than 12 hour, otherwise the input will not be handled.")
Console.Write("Please enter the amount of time blocks you require for your day: ")
blockNum = Console.ReadLine()
Dim timeA(blockNum - 1) As Integer
Dim timeB(blockNum - 1) As Integer
Dim sensitivity(blockNum - 1) As Integer
Dim ratio(blockNum - 1) As Integer
For i = 0 To (blockNum - 1)
Console.WriteLine("Please enter the start time of your time block")
timeA(i) = Console.ReadLine()
Console.WriteLine("Please enter the end time of your time block")
timeB(i) = Console.ReadLine()
Console.WriteLine("Please enter the ratio for this time block (Enter the amount of carbs that go into 1 unit of insulin)")
ratio(i) = Console.ReadLine()
Console.WriteLine("Please enter the insulin sensitivity for this time block
(amount of blood glucose (mmol/L) that is reduced by 1 unit of insulin.)")
sensitivity(i) = Console.ReadLine()
FileOpen(1, file, OpenMode.Append)
PrintLine(1, Convert.ToString(timeA(i)) + "-" + Convert.ToString(timeB(i)) + " 1:" + Convert.ToString(ratio(i)) + " Insulin Sensitivity:" + Convert.ToString(sensitivity(i)) + " per mmol/L")
FileClose(1)
Next
End Sub
Basically, I want the user to be able to enter a 4 digit number for their time block, to match a 24 hr time, so if they enter 0000, it is displayed as this, however, it removes all previous 0's and sets it to just 0.
Perhaps pad the number with 4 leading 0's:
Right(String(digits, "0") & timeA(i), 4)
Or as an alternative, store the value as a string so that it can be printed out in its original form.
I have written a Function to get a 24 hours format time from user, I hope it would help:
Public Function Read24HFormatTime() As String
Dim str As String = String.Empty
While True
Dim c As Char = Console.ReadKey(True).KeyChar
If c = vbCr Then Exit While
If c = vbBack Then
If str <> "" Then
str = str.Substring(0, str.Length - 1)
Console.Write(vbBack & " " & vbBack)
End If
ElseIf str.Length < 5 Then
If Char.IsDigit(c) OrElse c = ":" Then
If str.Length = 0 Then
' allow 0, 1 or 2 only
If c = "0" OrElse c = "1" OrElse c = "2" Then
Console.Write(c)
str += c
End If
ElseIf str.Length = 1 Then
If str = "0" Then
'allow 1 to 9
If c <> ":" Then
If CInt(c.ToString) >= 1 AndAlso CInt(c.ToString) <= 9 Then
Console.Write(c)
str += c
End If
End If
ElseIf str = "1" Then
'allow 0 to 9
If c <> ":" Then
If CInt(c.ToString) >= 0 AndAlso CInt(c.ToString) <= 9 Then
Console.Write(c)
str += c
End If
End If
ElseIf str = "2" Then
'allow 0 to 4
If c <> ":" Then
If CInt(c.ToString) >= 0 AndAlso CInt(c.ToString) <= 4 Then
Console.Write(c)
str += c
End If
End If
End If
ElseIf str.Length = 2 Then
'allow ":" only
If c = ":" Then
Console.Write(c)
str += c
End If
ElseIf str.Length = 3 Then
If str = "24:" Then
'allow 0 only
If c = "0" Then
Console.Write(c)
str += c
End If
Else
'allow 0 to 5
If c <> ":" Then
If CInt(c.ToString) >= 0 AndAlso CInt(c.ToString) <= 5 Then
Console.Write(c)
str += c
End If
End If
End If
ElseIf str.Length = 4 Then
If str.Substring(0, 3) = "24:" Then
'allow 0 only
If c = "0" Then
Console.Write(c)
str += c
End If
Else
'allow 0 to 9
If c <> ":" Then
If CInt(c.ToString) >= 0 AndAlso CInt(c.ToString) <= 9 Then
Console.Write(c)
str += c
End If
End If
End If
End If
End If
End If
End While
Return str
End Function
The user can only enter time like 23:59 08:15 13:10 and he couldn't enter formats like 35:10 90:00 25:13 10:61
This is a sample code to show you how to use it:
Dim myTime = DateTime.Parse(Read24HFormatTime())
Dim name = "Emplyee"
Console.WriteLine($"{vbCrLf}Hello, {name}, at {myTime:t}")
Console.ReadKey(True)

How can I extract the 'logical_test' from an if statement in excel?

I'm putting together an excel spreadsheet for calculations, and I need to be able to show the formulas to go with the decisions, for the most part its pretty straight forward, but When I come to an 'if' formula in an excel cell, I don't want to show the value_if_true and value_if_false... Just the logical_test value.
Example:
Formula is: =if(and(5<=A1, A1<=10),"Pass", "Fail");
Result will be: "and(5<=A1, A1<=10)"
I need to be able to work with complex logical tests which may include nested if statements, so just splitting at the commas won't work reliably. Similarly the value_if_true and value_if_false statements could also contain if statements.
Any ideas?
If have clear understanding of what you asking for, then you can use something like this (shall be used only with IF() statement :
Function extrIf(ByVal ifstatement As Range) As String
Dim S$, sRev$, x%, k
S = Replace(Replace(ifstatement.Formula, "IF(", "\"), "),", ")|")
sRev = StrReverse(S)
If InStr(1, sRev, "|") > InStr(1, sRev, "\") Or InStr(1, sRev, "|") = 0 Then
x = InStr(1, StrReverse(Left(sRev, InStr(1, sRev, "\"))), ",") - 1
S = Mid(S, 1, Len(S) - InStr(1, sRev, "\") + x) & "|"
End If
sRev = ""
For Each k In Split(S, "|")
If k <> "" Then
If k Like "*\*" Then
sRev = sRev & ", " & Mid(k, InStr(1, k, "\") + 1, 999)
End If
End If
Next
extrIf = Mid(sRev, 3, 999)
End Function
example:
test:
Maybe this is not complete solution for you, but I think it might give you right direction.
If the cell formula starts with an If statement then you can return the logic test (starting after the first open parenthesis) by determining the position of the first comma where the sum of the previous open parenthesis - the sum previous closed = 0.
Formulas
Function ExtractIfTest(Target As Range) As String
Dim ch As String, s As String
Dim openP As Long
Dim x As Long
s = Target.formula
For x = 5 To Len(s)
ch = Mid(s, x, 1)
If Mid(s, x, 1) = "(" Then
openP = openP + 1
ElseIf Mid(s, x, 1) = ")" Then
openP = openP - 1
ElseIf Mid(s, x, 1) = "," And openP = 0 Then
ExtractIfTest = Mid(s, 5, x - 12)
End If
Next
End Function
Results
There might be instances where the is a comma without parenthesis A1,B1. If this happens simple escape them with parenthesis (A1,B1)
I've written an UDF that extract any of the parameters of the target formula. It's close to the one in Thomas answer, but more global and takes into account strings that can enclose commas or parenthesis.
Function ExtractFormulaParameter(Target As Range, Optional Position As Long = 1) As Variant
Dim inString As Boolean
Dim formula As String
Dim st As Long, sp As Long, i As Long, c As String
Dim parenthesis As Long, comma As Long
formula = Target.formula
st = 0: sp = 0
If Position <= 0 Then ExtractFormulaParameter = CVErr(xlErrValue): Exit Function
For i = 1 To Len(formula)
c = Mid$(formula, i, 1)
If inString Then
If c = """" Then
inString = False
End If
Else
Select Case c
Case """"
inString = True
Case "("
parenthesis = parenthesis + 1
If parenthesis = 1 And Position = 1 Then
st = i + 1
End If
Case ")"
parenthesis = parenthesis - 1
If parenthesis = 0 And sp = 0 Then sp = i: Exit For
Case ","
If parenthesis = 1 Then
comma = comma + 1
If Position = 1 And comma = 1 Then sp = i: Exit For
If Position > 1 And comma = Position - 1 Then st = i + 1
If Position > 1 And comma = Position Then sp = i: Exit For
End If
Case Else
End Select
End If
Next i
If st = 0 Or sp = 0 Then
ExtractFormulaParameter = CVErr(xlErrNA)
Else
ExtractFormulaParameter = Mid$(formula, st, sp - st)
End If
End Function
By default it returns the first parameter, but you can also return the second or the third, and it should work with any formula.
Thanks for the replies all. I thought about this more, and ended up coming up with a similar solution to those posted above - essentially string manipulation to extract the text where we expect to find the logical test.
Works well enough, and I'm sure I could use it to extract further logical tests from substrings too.

array without any duplicate value

the code to generate no. of arrays from one is working..I'm try to make some change to it like below
Function myarray(ByVal arra1() As Integer, ByVal arran() As Integer, ByVal arrNumber As Integer) As Integer()
arran = arra1.Clone()
For i As Integer = 0 To arra1.Length - 1
If i = (arrNumber - 1) Then ' IF arrNumber is 1 then +1 to index 0, If it is 2 then +1 to index 1
arran(i) = arra1(i) + 1
'If there are two duplicate value make on of them zero at a time
For k = 0 To arran.Length - 1
For j = k + 1 To arran.Length - 1
If arran(k) = arran(j) Then
arran(k) = 0
End If
'make any value great than 11 zero
If arran(i) > 11 Then
arran(i) = 0
End If
Next
Next
Else
arran(i) = arra1(i)
End If
Next
'Print the array
For i = 0 To arran.Length - 1
Console.Write(arran(i) & " ")
Next
Console.WriteLine()
Return arran
End Function
what I really need is to decompose for example {1,4,5,5} to be {1,4,0,5} and then {1,4,5,0} the above code generate only {1,4,0,5}
I haven't tested this, but I believe the following code will do what you want. Based on your comments, I've changed the function to return all resulting arrays as an array of arrays, rather than requiring the index to change as an input and returning one array. I also ignored matches of 0, as the conditions you describe don't seem designed to handle them. Because of it's recursion, I think this approach will successfully handle input such as {3, 3, 3, 3}.
Public Function jaggedArray(ByVal inputArray() As Integer) As Integer()()
If inputArray Is Nothing Then
Return Nothing
Else
Dim resultArrays()(), i, j As Integer
Dim arrayMax As Integer = inputArray.GetUpperBound(0)
If arrayMax = 0 Then 'prevents errors later if only one number passed
ReDim resultArrays(0)
If inputArray(0) > 11 Then
resultArrays(0) = {1}
ElseIf inputArray(0) = 11 Then
resultArrays(0) = {0}
Else
resultArrays(0) = {inputArray(0) + 1}
End If
Return resultArrays
End If
For i = 0 To arrayMax
Dim tempArray() As Integer = inputArray.Clone
For j = 0 To arrayMax
If tempArray(j) > 11 Then
tempArray(j) = 0
End If
Next
If tempArray(i) = 11 Then
tempArray(i) = 0
Else
tempArray(i) += 1
End If
splitArray(resultArrays, tempArray)
Next
Return resultArrays
End If
End Function
Private Sub splitArray(ByRef arrayList()() As Integer, ByVal sourceArray() As Integer)
Dim x, y As Integer 'positions of matching numbers
If isValid(sourceArray, x, y) Then
If arrayList Is Nothing Then
ReDim arrayList(0)
Else
ReDim Preserve arrayList(arrayList.Length)
End If
arrayList(arrayList.GetUpperBound(0)) = sourceArray
Else
Dim xArray(), yArray() As Integer
xArray = sourceArray.Clone
xArray(x) = 0
splitArray(arrayList, xArray)
yArray = sourceArray.Clone
yArray(y) = 0
splitArray(arrayList, yArray)
End If
End Sub
Private Function isValid(ByRef testArray() As Integer, ByRef match1 As Integer, ByRef match2 As Integer) As Boolean
For i As Integer = 0 To testArray.GetUpperBound(0) - 1
If testArray(i) > 11 Then
testArray(i) = 0
End If
For j As Integer = i + 1 To testArray.GetUpperBound(0)
If testArray(j) > 11 Then
testArray(j) = 0
End If
If testArray(i) = testArray(j) AndAlso testArray(i) > 0 Then 'added second test to prevent infinite recursion
match1 = i
match2 = j
Return False
End If
Next
Next
match1 = -1
match2 = -1
Return True
End Function

convert a text to a number

I don't know why this code doesn't work ..i wanna just convert text to number .. It doesn't give me any error but it doesn't work
Public Function ConvertCOMPLEXITYToNumber(ByVal chain As String) As Integer
Select Case chain
Case "1 - Très difficile"
ConvertCOMPLEXITYTToNumber = 1
Case "2 - Difficile"
ConvertCOMPLEXITYTToNumber = 2
Case "3 - Modérée"
ConvertCOMPLEXITYTToNumber = 3
Case "4 - Facile"
ConvertCOMPLEXITYTToNumber = 4
Case Else
ConvertCOMPLEXITYTToNumber = 0
End Select
Exit Function
End Function
That may be because you may have unwanted leading or trailing spaces which fails the comparison. Also you do not need Exit Function at the end of the code. It will exit any ways :)
Try this
Public Function ConvertCOMPLEXITYToNumber(ByVal chain As String) As Integer
Dim Num As Integer
Select Case Trim(chain)
Case "1 - Très difficile": Num = 1
Case "2 - Difficile": Num = 2
Case "3 - Modérée": Num = 3
Case "4 - Facile": Num = 4
Case Else: Num = 0
End Select
ConvertCOMPLEXITYToNumber = Num
End Function
If IsNumeric(Left(Trim(chain),1)) Then
ConvertCOMPLEXITYToNumber = Left(Trim(chain),1)
Else
ConvertCOMPLEXITYToNumber = 0
End If
Here, my approach for you:
Public Function ConvertCOMPLEXITYToNumber(ByVal chain As String) As Integer
'Get the first character
chain = Left(Trim(chain), 1)
'If frist character is numeric
If IsNumeric(chain) Then
'If first number is less than 5, return value
If chain < 5 Then
ConvertCOMPLEXITYToNumber = CInt(chain)
End If
End If
End Function

Calculate words value in vb.net

I have a textbox on a form where the user types some text. Each letter is assigned a different value like a = 1, b = 2, c = 3 and so forth. For example, if the user types "aa bb ccc" the output on a label should be like:
aa = 2
bb = 4
dd = 6
Total value is (12)
I was able to get the total value by looping through the textbox string, but how do I display the total for each word. This is what I have so far:
For letter_counter = 1 To word_length
letter = Mid(txtBox1.Text, letter_counter, 1)
If letter.ToUpper = "A" Then
letter_value = 1
End If
If letter.ToUpper = "B" Then
letter_value = 2
End If
If letter.ToUpper = "C" Then
letter_value = 3
End If
If letter.ToUpper = "D" Then
letter_value = 4
End If
If letter.ToUpper = "E" Then
letter_value = 5
End If
If letter.ToUpper = " " Then
letter_value = 0
End If
totalletter = totalletter + letter_value
Label1.Text = Label1.Text & letter_value & " "
txtBox2.Text = txtBox2.Text & letter_value & " "
Next letter_counter
This simple little routine should do the trick:
Private Sub CountLetters(Input As String)
Label1.Text = ""
Dim total As Integer = 0
Dim dicLetters As New Dictionary(Of Char, Integer)
dicLetters.Add("a"c, 1)
dicLetters.Add("b"c, 5)
dicLetters.Add("c"c, 7)
For Each word As String In Input.Split
Dim wordtotal As Integer = 0
For Each c As Char In word
wordtotal += dicLetters(Char.ToLower(c))
Next
total += wordtotal
'Display word totals here
Label1.Text += word.PadRight(12) + "=" + wordtotal.ToString.PadLeft(5) + vbNewLine
Next
'Display total here
Label1.Text += "Total".PadRight(12) + "=" + total.ToString.PadLeft(5)
End Sub
This should give you an idea:
Dim listOfWordValues As New List(Of Integer)
For letter_counter = 1 To word_length
letter = Mid(txtBox1.Text, letter_counter, 1)
If letter = " " Then
totalletter= totalletter + letter_value
listOfWordValues.Add(letter_value)
letter_value = 0
Else
letter_value += Asc(letter.ToUpper) - 64
End If
Next letter_counter
totalletter = totalletter + letter_value
If Not txtBox1.Text.EndsWith(" ") Then listOfWordValues.Add(letter_value)
txtBox2.Text = txtBox2.Text & string.Join(", ", listOFWordValues);
You can try something like this. Assuming txtBox1 is the string the user enters and " " (space) is the word delimiter:
Dim words As String() = txtBox1.Text.Split(New Char() {" "}, StringSplitOptions.RemoveEmptyEntries)
Dim totalValue As Integer = 0
Dim wordValue As Integer = 0
For Each word As String In words
wordValue = 0
For letter_counter = 1 To word.Length
Dim letter As String = Mid(txtBox1.Text, letter_counter, 1)
Select letter.ToUpper()
Case "A":
wordValue = wordValue + 1
Case "B":
wordValue = wordValue + 2
' And so on
End Select
Next
totalValue = toalValue + wordValue
Next
The above code first takes the entered text from the user and splits it on " " (space).
Next it sets two variables - one for the total value and one for the individual word values, and initializes them to 0.
The outer loop goes through each word in the array from the Split performed on the user entered text. At the start of this loop, it resets the wordValue counter to 0.
The inner loop goes through the current word, and totals up the values of the letter via a Select statement.
Once the inner loop exits, the total value for that word is added to the running totalValue, and the next word is evaluated.
At the end of these two loops you will have calculated the values for each word as well as the total for all the worlds.
The only thing not included in my sample is updating your label(s).
Try this ..
Dim s As String = TextBox1.Text
Dim c As String = "ABCDE"
Dim s0 As String
Dim totalletter As Integer
For x As Integer = 0 To s.Length - 1
s0 = s.Substring(x, 1).ToUpper
If c.Contains(s0) Then
totalletter += c.IndexOf(s0) + 1
End If
Next
MsgBox(totalletter)
I would solve this problem using a dictionary that maps each letter to a number.
Private Shared ReadOnly LetterValues As Dictionary(Of Char, Integer) = GetValues()
Private Shared Function GetValues() As IEnumerable(Of KeyValuePair(Of Char, Integer))
Dim values As New Dictionary(Of Char, Integer)
Dim value As Integer = 0
For Each letter As Char In "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
value += 1
values.Add(letter, value)
Next
Return values
End Function
Public Function CalculateValue(input As String) As Integer
Dim sum As Integer = 0
For Each letter As Char In input.ToUpperInvariant()
If LetterValues.ContainsKey(letter) Then
sum += LetterValues.Item(letter)
End If
Next
Return sum
End Function
Usage example:
Dim sum As Integer = 0
For Each segment As String In "aa bb ccc".Split()
Dim value = CalculateValue(segment)
Console.WriteLine("{0} = {1}", segment, value)
sum += value
Next
Console.WriteLine("Total value is {0}", sum)
' Output
' aa = 2
' bb = 4
' ccc = 9
' Total value is 15