Counting blank text box as 0 value While Text Boxes are Empty - vb.net

I am have written the following code:
Dim i As Integer
Dim pos As Integer = 0
Dim neg As Integer = 0
Dim zer As Integer = 0
Dim TextBoxes() As String = {Val(TextBox1.Text), Val(TextBox2.Text),
Val(TextBox3.Text), Val(TextBox4.Text),
Val(TextBox5.Text), Val(TextBox6.Text),
Val(TextBox7.Text), Val(TextBox8.Text),
Val(TextBox9.Text), Val(TextBox10.Text)}
For i = 0 To 9
If TextBoxes(i) > 0 Then
pos += 1
End If
If TextBoxes(i) < 0 Then
neg += 1
End If
If TextBoxes(i) = 0 Then
zer += 1
End If
Next i
Label4.Text = (pos)
Label5.Text = (neg)
Label6.Text = (zer)
When the program executes and I put some values into the text boxes, the output looks like this. The first text box contains 1 which is positive and the other one contains -1 which is negative. It's working well.
The problem occurs here: the program is counting the empty boxes as 0 and displaying 8 in the total number of zeros. All of the other 8 text boxes were left blank. How can I Fix the issue so that it doesn't count the empty text boxes as 0.
For reference, here is my related, previous problem which has already been solved: Finding String of Substring in VB without using library function

The problem is that you are calling the Val function to get the value in each text box. Val returns 0 if the given text is empty or non-numeric. If you want to check that, you should just store the original strings in the array and then check the value in the loop, like this:
Dim i As Integer
Dim pos As Integer = 0
Dim neg As Integer = 0
Dim zer As Integer = 0
Dim TextBoxes() As String = {TextBox1.Text, TextBox2.Text,
TextBox3.Text, TextBox4.Text,
TextBox5.Text, TextBox6.Text,
TextBox7.Text, TextBox8.Text,
TextBox9.Text, TextBox10.Text}
For i = 0 To 9
If TextBoxes(i) <> String.Empty Then
If Val(TextBoxes(i)) > 0 Then
pos += 1
End If
If Val(TextBoxes(i)) < 0 Then
neg += 1
End If
If Val(TextBoxes(i)) = 0 Then
zer += 1
End If
End If
Next i
Label4.Text = pos.ToString()
Label5.Text = neg.ToString()
Label6.Text = zer.ToString()
However, the Val function is mainly just provided for backwards compatibility with VB6. It will work, but I would recommend using Integer.TryParse instead. Note that I also added ToString to the last three lines. As others have mentioned, it would behoove you to turn Option Strict On.

Related

How can put split integers in a two-dimensional array?

I making matrix calculator. so, Textbox_A contains vbCrLf and tries to put it in Array_A.
and I would like to put Array_A in Result Matrix.
It's like
Textbox_a:
(1 2 3)
(4 5 6)
[Matrix to Array]
Array_a(0)(0) = 1
Array_a(0)(1) = 2
Array_a(0)(2) = 3
Array_a(1)(0) = 4
...
I have done string splits through several articles, but changing them to integers causes many problems.
This picture is Matrix_A and result Matrix
I don't know if the size of your initial matrix, formatted as text, is fixed, but here is some code to help you get started. The code tries to calculate the number of columns and rows.
The actual code is in the TextToArray function, that takes as input as string formatted as you described:
(1 2 3) (cr/lf)
(4 5 6)
and outputs a two dimensional array. The Main sub is just used to call TextToArray and display results.
So, in your example, you should pass TextBox_A.Text to TextToArray
There is minimal error checking here - you should add more to validate that data entered are numbers (check the Integer.TryParse function) and that the number of columns is the same across lines.
Sub Main(args As String())
Dim myInput As String = "(1 2 3)" & vbCrLf & "(4 5 6)"
Dim ret As Integer(,) = TextToArray(myInput)
If ret IsNot Nothing Then
For i As Integer = 0 To ret.GetUpperBound(0) - 1
For n As Integer = 0 To ret.GetUpperBound(1) - 1
Console.WriteLine(i & "," & n & "=" & ret(i, n))
Next
Next
Else
Console.WriteLine("No results - wrong input format")
End If
Console.ReadLine()
End Sub
Private Function TextToArray(matrix As String) As Integer(,)
Dim noOfRows As Integer = matrix.Split(vbCrLf).Count
Dim noOfColumns As Integer = 0
If noOfRows > 0 Then
noOfColumns = matrix.Split(vbCrLf)(0).Split(" ").Count
End If
If noOfColumns > 0 And noOfRows > 0 Then
Dim ret(noOfRows, noOfColumns) As Integer
Dim lines As String() = matrix.Split(vbCrLf)
Dim row As Integer = 0
For Each line As String In lines
Dim col As Integer = 0
line = line.Replace("(", "")
line = line.Replace(")", "")
For Each s As String In line.Split(" ")
ret(row, col) = Integer.Parse(s)
col += 1
Next
row += 1
Next
Return ret
Else
Return Nothing
End If
End Function
This outputs:
0,0=1
0,1=2
0,2=3
1,0=4
1,1=5
1,2=6

Splitting string every 100 characters not working

I am having a problem where I just can't seem to get it to split or even display the message. The message variable is predefined in another part of my code and I have debugged to make sure that the value comes through. I am trying to get it so that every 100 characters it goes onto a new line and with every message it also goes onto a new line.
y = y - 13
messagearray.AddRange(Message.Split(ChrW(100)))
Dim k = messagearray.Count - 1
Dim messagefin As String
messagefin = ""
While k > -1
messagefin = messagefin + vbCrLf + messagearray(k)
k = k - 1
End While
k = 0
Label1.Text = Label1.Text & vbCrLf & messagefin
Label1.Location = New Point(5, 398 + y)
You can use regular expression. It will create the array of strings where every string contains 100 characters. If the amount of remained characters is less than 100, it will match all of them.
Dim input = New String("A", 310)
Dim mc = Regex.Matches(input, ".{1,100}")
For Each m As Match In mc
'// Do something
MsgBox(m.Value)
Next
You can use LINQ to do that.
When you do a Select you can get the index of the item by including a second parameter. Then group the characters by that index divided by the line length so, the first character has index 0, and 0 \ 100 = 0, all the way up to the hundredth char which has index 99: 99 \ 100 = 0. The next hundred chars have 100 \ 100 = 1 to 199 \ 100 = 1, and so on (\ is the integer division operator in VB.NET).
Dim message = New String("A"c, 100)
message &= New String("B"c, 100)
message &= New String("C"c, 99)
Dim lineLength = 100
Dim q = message.Select(Function(c, i) New With {.Char = c, .Idx = i}).
GroupBy(Function(a) a.Idx \ lineLength).
Select(Function(b) String.Join("", b.Select(Function(d) d.Char)))
TextBox1.AppendText(vbCrLf & String.Join(vbCrLf, q))
It is easy to see how to change the line length because it is in a variable with a meaningful name, for example I set it to 50 to get the output
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
You can use String.SubString to do that. Like this
Dim Message As String = "your message here"
Dim MessageList As New List (Of String)
For i As Integer = 0 To Message.Length Step 100
If (Message.Length < i + 100) Then
MessageList.Add(Message.SubString (i, Message.Length - i)
Exit For
Else
MessageList.Add(Message.SubString (i, 100))
End If
Next
Dim k = MessageList.Count - 1
...
Here is what your code produced with a bit of clean up. I ignored the new position of the label.
Private Sub OpCode()
Dim messagearray As New List(Of String) 'I guessed that messagearray was a List(Of T)
messagearray.AddRange(Message.Split(ChrW(100))) 'ChrW(100) is lowercase d
Dim k = messagearray.Count - 1
Dim messagefin As String
messagefin = ""
While k > -1
messagefin = messagefin + vbCrLf + messagearray(k)
k = k - 1
End While
k = 0 'Why reset k? It falls out of scope at End Sub
Label1.Text = Label1.Text & vbCrLf & messagefin
End Sub
I am not sure why you think that splitting a string by lowercase d would have anything to do with getting 100 characters. As you can see the code reversed the order of the list items. It also added a blank line between the existing text in the label (In this case Label1) and the new text.
To accomplish your goal, I first created a List(Of String) to store the chunks. The For loop starts at the beginning of the input string and keeps going to the end increasing by 10 on each iteration.
To avoid an index out of range which would happen at the end. Say, we only had 6 characters left from start index. If we tried to retrieve 10 characters we would have an index out of range.
At the end we join the elements of the string with the separated of new line.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BreakInto10CharacterChunks("The quick brown fox jumped over the lazy dogs.")
End Sub
Private Sub BreakInto10CharacterChunks(input As String)
Dim output As New List(Of String)
Dim chunk As String
For StartIndex = 0 To input.Length Step 10
If StartIndex + 10 > input.Length Then
chunk = input.Substring(StartIndex, input.Length - StartIndex)
Else
chunk = input.Substring(StartIndex, 10)
End If
output.Add(chunk)
Next
Label1.Text &= vbCrLf & String.Join(vbCrLf, output)
End Sub
Be sure to look up String.SubString and String.Join to fully understand how these methods work.
https://learn.microsoft.com/en-us/dotnet/api/system.string.substring?view=netframework-4.8
and https://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8

Conditional formatting of DataGridView cell data - Change color on negative

I was hoping to be able to use color based conditional formatting in the DefaultCellStyle.Format field for DataGridView cells, in a similar way to how Excel handles this.
For example in Excel, a format string of £#,##0.00;[Red]-£#,##0.00 will display negative values in red.
Is this supported in VB.NET ?
I am aware I can use the .CellFormatting event to conditionally change cell text color but was looking for a less bulky and restrictive way of doing this.
By creating the following CellFormatting addition, I am able to use Excel style conditional colour formatting in the cells format field. Setting the colour for negative/positive/zero values is supported.
Format string is expected to be in the following format (all colours optional) :
[colour]<format for +value> ; [colour]<format for -value> ; [colour]<format for zero value>
..a test DGV column with conditional formatting
c = New DataGridViewColumn
c.Name = "AmountOUT"
c.DataPropertyName = c.Name
c.HeaderText = "AmountOUT"
c.CellTemplate = New DataGridViewTextBoxCell
c.DefaultCellStyle.Format = "[Green]£0.00;[Red]-£0.00;[Blue]zero"
.Columns.Add(c)
..
Private Sub DataGridView1_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
'Split format string to positive / negative / zero components
Dim posnegzero As List(Of String)
posnegzero = e.CellStyle.Format.Split(CChar(";")).ToList
Dim coloursPNZ As New List(Of String)
Dim remainderformatPNZ As String = ""
For Each s As String In posnegzero
If s.Contains("[") And s.Contains("]") Then
'Extract [xxx] contents
coloursPNZ.Add(s.Substring(s.IndexOf("[") + 1, s.IndexOf("]") - s.IndexOf("[") - 1))
'Append rebuilt format excluding [xxx]
remainderformatPNZ &= s.Substring(0, s.IndexOf("[")) & s.Substring(s.IndexOf("]") + 1, s.Length - s.IndexOf("]") - 1) & ";"
Else
coloursPNZ.Add("")
remainderformatPNZ &= s & ";"
End If
Next
'Set format excluding any [xxx] components
e.CellStyle.Format = remainderformatPNZ
'Check for positive value
If Val(e.Value) > 0 And coloursPNZ.Count >= 1 Then
If coloursPNZ(0) <> "" Then
e.CellStyle.ForeColor = Color.FromName(coloursPNZ(0))
End If
End If
'Check for negative value
If Val(e.Value) < 0 And coloursPNZ.Count >= 2 Then
If coloursPNZ(1) <> "" Then
e.CellStyle.ForeColor = Color.FromName(coloursPNZ(1))
End If
End If
'Check for zero value
If Val(e.Value) = 0 And coloursPNZ.Count >= 3 Then
If coloursPNZ(2) <> "" Then
e.CellStyle.ForeColor = Color.FromName(coloursPNZ(2))
End If
End If
End Sub
Dim dgv As DataGridView = Me.DataGridView1
For i As Integer = 0 To dgv.Rows.Count - 1
For ColNo As Integer = 4 To 7 ' number columns
If Not dgv.Rows(i).Cells(ColNo).Value < 0 Then
dgv.Rows(i).Cells(ColNo).Style.BackColor = vbcolor.Red
End If
Next
Next
checking for negative values lookout for strings format and check accordingly
Tryparse will convert the input to an integer if it succeeds - you don't need both the comps and value variables. Here's an example of how it works:
Dim comps As Integer
Dim input As String = "im not an integer"
Dim input2 As String = "2"
'tryparse fails, doesn't get into comps < 0 comparison
If Integer.TryParse(input, comps) Then
If comps < 0 Then
'do something
End If
Else
'I'm not an integer!
End If
'tryparse works, goes into comps < 0 comparison
If Integer.TryParse(input2, comps) Then
If comps < 0 Then
'do something
End If
End If

Detect the closing bracket belong to the open bracket when there is more than one open & close bracket inside the bracket

Actually, I want to do this to detect the value inside the rounding bracket and do the rounding to whatever inside the rounding bracket. For example:
Dim h As String = "ROUNDING(30.98998(10))*2+3"
Dim r As String = h.ToString.Substring(h.ToString.IndexOf("ROUNDING(") + 1, h.ToString.IndexOf(")") - 1 - h.ToString.IndexOf("ROUNDING("))
In this case, after the ROUNDING( there is one more ( and ). How to make the open bracket on the ROUNDING to match to the end of it's closing bracket?
Thanks in advance!
You could use the following ReadInBetweenSameDepth Function.
Public Function ReadInBetweenSameDepth(str As String, delimiterStart As Char, delimiterEnd As Char) As String
If delimiterStart = delimiterEnd OrElse String.IsNullOrWhiteSpace(str) OrElse str.Length <= 2 Then
Return Nothing
End If
Dim delimiterStartFound As Integer = 0
Dim delimiterEndFound As Integer = 0
Dim posStart As Integer = -1
For i As Integer = 0 To str.Length - 1
If str(i) = delimiterStart Then
If i >= str.Length - 2 Then
'delimiter start is found in any of the last two characters
Return Nothing
End If
'it means, there isn't anything in between the two
If delimiterStartFound = 0 Then
'first time
posStart = i + 1
End If
'assign the starting position only the first time...
'increase the number of delimiter start count to get the same depth
delimiterStartFound += 1
End If
If str(i) = delimiterEnd Then
delimiterEndFound += 1
If delimiterStartFound = delimiterEndFound AndAlso i - posStart > 0 Then
Return str.Substring(posStart, i - posStart)
'only successful if both delimiters are found in the same depth
End If
End If
Next
Return Nothing
End Function
It basically checks if the delimiters (such as ( and ) ) are in the same "depth".

Count specific character in string using SubString

I'm teaching myself VB.net and I'm trying to complete challenges.
I'm stuck on this challenge.
I'm trying to figure out how to go about counting specific characters in a string using SubString.
I should not use string processing functions other than: Trim, ToUpper, ToLower, Indexof, SubString.
Add one button for each vowel of the alphabet. When clicked, the output is the count of that vowel in the text entered.Using SubString, the code under the button click event handler,displays how many times the corresponding character appears in the text.
This is what I have so far, but how should I incorporate SubString?
Dim counter As Integer = 0
For Each vowelA As Char In TextBox1.Text
If vowelA = "a" Then
counter += 1
End If
If vowelA = "A" Then
counter += 1
End If
Next
Here I incorporated also .ToUpper so you don't need to compare "a" and "A"
Dim counter As Integer = 0
For i = 0 To TextBox1.Text.Length - 1
If TextBox1.Text.ToUpper.Substring(i, 1) = "A" Then
counter += 1
End If
Next
Without using a substring() function,
Function count_vowels(ByVal str As String, ByVal chr As String) As Integer
str = str.ToUpper()
chr = chr.ToUpper()
count_vowels = str.Split(chr).Length - 1
Return count_vowels
End Function
Usage:
Dim counter As Integer = 0
counter = count_vowels(TextBox3.Text, "a")
or simply use
counter = TextBox1.Text.ToUpper.Split("a".ToUpper).Length - 1
Try something like this:
Dim pos As Integer = 0
Dim letter as String
While pos < TextBox1.Text.Length
letter = TextBox1.Text.Substring(pos, 1)
If letter = "A" Then
counter += 1
End If
pos += 1
End While