I need to check if an input comes null/empty.
If input <= 100 And input > 0 And Not input = "" Then
subjectsInt.Add(subjects(i), input)
check = True
End If
I know in that code I am checking it as String but I already did Not input = Nothing and Not input = 0 and I am getting an error:
Run-time exception (line -1): Conversion from string "" to type 'Integer' is not valid.
Stack Trace:
[System.FormatException: Input string was not in a correct format.]
[System.InvalidCastException: Conversion from string "" to type 'Integer' is not valid.]
Any suggestions?
EDIT
Here is the code in case you want to take a look: https://dotnetfiddle.net/0QvoAo
Well, I have looked at your code and there are many problems, all caused by the freely approach to Data Types that VB.NET allows when you have Option Strict set to Off. In this context VB.NET allows you to assign the return value of Console.ReadLine to an Integer trying to help you adding an implicit conversion of the input. Of course if the user types ABCD this implicit conversion has no other way to inform you than triggering an Exception. So I really, really recommend you to use Option Strict set to On (MSDN Option Strict)
Now with Option Strict On your code has a lot of errors, I have rewritten your code and then explain in comments the changes.
Option Strict On
Imports System
Imports System.Collections.Generic
Public Module Module1
Public Sub Main()
Console.WriteLine("Hello World")
' I use a List of strings instead of an untyped array list
Dim subjects As New List(Of String)() From
{
"Math",
"English",
"German"
}
Dim subjectsInt As New System.Collections.Generic.Dictionary(Of String, Integer)
Dim i, input As Integer
Dim check As Boolean
For i = 0 To subjects.Count - 1
check = False
Do
Console.WriteLine(subjects(i) & ": ")
' The input is passed to a string
Dim temp = Console.ReadLine()
' Check if this string is really a number
If Int32.TryParse(temp, input) Then
If input <= 100 And input > 0 Then
subjectsInt.Add(subjects(i), input)
check = True
End If
End If
Loop While check = False
Next
For i = 0 To subjects.Count - 1
Console.WriteLine(subjects(i) & ": " & subjectsInt(subjects(i)))
Next
Console.ReadLine()
End Sub
End Module
The error is telling you that the input is an integer, you can't compare an integer with a string which is precisely what's happening.
Even if the string contains only digit, the type system doesn't convert it inferring from the operator.
In your example, input = "" input can never be "". You should change the type of input to a string and then check before converting it to an integer.
This would be a solution:
Dim integerInput As Integer
Dim stringInput = Console.ReadLine()
If Integer.TryParse(stringInput, integerInput) AndAlso integerInput <= 100 And integerInput > 0 Then
To use < > = with an integer you need to convert the string:
If Integer.Parse(input) <= 100 And Integer.Parse(input) > 0 And Not input = "" Then
Integer.Parse will do the job.
Obviously, if your input is a string and it's not guaranteed that it is going to contain just digit you need either to do some check before or use Integer.TryParse.
The closest you can get to a null check with a value type is EqualityComparer(Of Integer).Default.Equals(id, Nothing); unless you start using Nullable, but it would be too late as the code will fail on the input = Console.ReadLine() when you input a non-digit string.
Related
I'm new to Visual Basics, and I tried implementing input validation for the Mark input in my application where the input can't be empty or < 0 or > 100 or isnumeric(Mark) = False or else an error message would be displayed. However, I tried leaving the input as empty or entering alphabetical values but it returned me a run time error instead. Could anyone assist me in some explanations as well as how to overcome this? Apologies if this is a dumb question.
Note: The data type for the variable "Mark" is set as single. Thank you for your time!
Sub InputMark()
4: For I = 0 To 3
Console.WriteLine("Please enter test marks for test " & I + 1)
Mark(I) = Console.ReadLine
While Mark(I) = Nothing Or Mark(I) < 0 Or Mark(I) > 100 Or IsNumeric(Mark(I)) = False
Console.WriteLine("Please enter valid test marks.")
GoTo 4
End While
Next
End Sub
A couple of things:
Turn option strict on: https://github.com/dday9/vb.net-tutorial/blob/master/Section%201/Chapter%201.md
Using Single.TryParse on the result of ReadLine.
ABANDON GOTO'! In this case a simple Do loop will suffice.
Take a look at this example:
Option Strict On
Option Explicit On
Imports System
Public Module Module1
Public Sub Main()
' Declare an array of Single values
Dim marks(3) As Single
' Loop from 0 to n (in this case 3)
For counter As Integer = 0 To marks.Length - 1
' Declare a variable to check if the conversion was succesful
Dim success As Boolean = False
' Start a Do/Until loop
Do
' Propt the user to enter something
Console.WriteLine("Please enter test marks for test " & counter + 1)
' Check if the conversion from ReadLine to a Single is valid
success = Single.TryParse(Console.ReadLine(), marks(counter)) AndAlso marks(counter) >= 0 AndAlso marks(counter) <= 100
' If not then scold the user
If (Not success) Then
Console.WriteLine("Please enter valid test marks.")
End If
Loop Until success
Next
' Debug - just print out the values of marks
For Each mark As Single In marks
Console.WriteLine(mark)
Next
End Sub
End Module
Live Demo: https://dotnetfiddle.net/guoAzP
The data type for the variable "Mark" is set as single.
One of the nice things about strongly-typed platforms like .Net is most of your validation rules are already enforced. You will not be able to assign a non-number value to Mark, and as a value-type it can't even be null (VB.Net's Nothing will evaluate to 0 for a Single type).
So what we need to do instead is back up, and find where the data is received from the user, before it's assigned to the Mark variable. Somewhere you'll have code like Mark(I) = Console.Readline(), or similar. That's where your testing needs to be. Check the string value received from the user before assigning it to the Single value. And when you come to that point, the best way to accomplish this testing is with the Single.TryParse() function. Then, you can verify the parsed Single value is within the correct range.
Okay, with more complete code we can start to give you some real improvements.
One suggestion is to think in terms of returning a value. It's better design to let this function return the array, rather than communicating through a global variable. I mention that here because it will also mean changing how you call this function.
That out of the way:
Function InputMarks() As Single()
Dim result(3) As Single
For I As Integer = 0 To 3
Dim ErrorMsg As String = ""
Do
Console.Write($"{ErrorMsg}Please enter test marks for test {I+1}: ")
Dim input As String = Console.ReadLine()
ErrorMsg = $"{vbCrLf}Please enter valid test marks.{vbCrLf}{vbCrLf}"
While Not Single.TryParse(input, result(I)) OrElse result(I) < 0 OrElse result(I) > 100
Next
Return result
End Function
No GOTO required or wanted.
If you haven't seen them yet, the $"strings" are using string interpolation and the OrElse operator instead of Or is to get short-circuiting behavior. Modern VB.Net should use OrElse and AndAlso instead of Or and And pretty much all the time.
In this case, using OrElse means we're sure Single.TryParse() completed successfully and we will have a valid number before attempting to verify the range. If the parse operation failed, the range tests won't even be attempted.
I'm going to break this into smaller functions.
First, here is a function to process a string, which returns either a number if it satisfies your conditions, or Single.NaN.
Private Function validateMarkOrNaN(input As String) As Single
Return If(Single.TryParse(input, validateMarkOrNaN) AndAlso 0 <= validateMarkOrNaN AndAlso validateMarkOrNaN <= 100, validateMarkOrNaN, Single.NaN)
End Function
Here is a second function which calls the first when it needs to process the user input. This function handles the flow of a single input. It can be called any number of times, requiring that you pass in the index only so it can be typed in the console.
Private Function getMarkInput(index As Integer) As Single
Dim result As Single
Do
Console.WriteLine($"Please enter test marks for test {index + 1}")
result = validateMarkOrNaN(Console.ReadLine())
If Single.IsNaN(result) Then Console.WriteLine("Please enter valid test marks.")
Loop While Single.IsNaN(result)
Return result
End Function
Your main program dictates the overall flow. Here you can declare how many marks will be read, and loop over your array, getting each input into each element.
Sub Main()
Dim numberOfMarks = 4
Dim Mark(numberOfMarks - 1) As Single
For i = 0 To numberOfMarks - 1
Mark(i) = getMarkInput(i)
Next
End Sub
Similar to your code, this will loop indefinitely as long as the user doesn't enter a valid float.
My program crashes when I enter letter characters into the input box or leave the input box blank. Why is my validation if statement not working?
Option Strict On
Public Class frmPickUpSticks
Dim playersTurn As Boolean = False
Dim remainingSticks As Integer 'count sticks
Dim losses As Integer = 0 'count player losses
Private Sub btnNewGame_Click(sender As Object, e As EventArgs) Handles btnNewGame.Click
lblOutput.Text = ""
remainingSticks = CInt(InputBox("How many matchsticks would you like (5 - 25)?", "Pick Number of Matches!"))
'Validate input
If IsNumeric(remainingSticks) Then
If (remainingSticks >= 5) And (remainingSticks <= 25) Then
DisplayMatches()
If (remainingSticks Mod 4 = 1) Then
MessageBox.Show("You go first!")
playersTurn = True
turns()
Else
MessageBox.Show("I go first.")
turns()
End If
Else
MessageBox.Show("Please enter a number between 5 and 25.")
End If
Else
MessageBox.Show("Input must be numeric.", "Input Error")
End If
You can't automatically take what your user types in an InputBox and pass this input to any function or method that expects a number for input. The InputBox method has been designed to return a string and this string need to be converted but you need to use methods that know how to parse a string. Otherwise methods that are not designed to handle nonnumeric values (CInt) will cause exceptions.
Instead you should try some kind of parsing and the NET Library offers many tools to use. In your case the correct one is Int32.TryParse
Dim remainingSticks As Integer
Dim userInput = InputBox("How many matchsticks .....")
If Int32.TryParse(userInput, remainingSticks) Then
.... ok your remainingStick contains the converted value
Else
MessageBox.Show("You should type a valid integer number between 5-25")
The Int32.TryParse will look at your input string and try to convert to a valid integer value. If it succeed then the second parameter contains the converted integer and returns True, if it fails it return false and your second parameter will have the default value of zero.
Of course after a succesfull conversion to an integer your don't need anymore a check with IsNumeric
You should use a string variable in the inputbox
dim st as string
st = InputBox("How many matchsticks would you like (5 - 25)?", "Pick Number of Matches!"))
remainingSticks = val(st)
. . .
I wanted to get familiar with the built-in functions of VB, specifically, the len() function.
However, I think this may not be the right way to concatenate a string with a char.
Also, it may interest you that the error list says,
"Warning 1 Variable 'reverse' is used before it has been assigned a
value. A null reference exception could result at runtime."
I executed the program but it ran fine. Here's the code:
Sub Main()
Dim a As String
Console.WriteLine("Enter the value of the string you want to reverse: ")
a = Console.ReadLine()
Dim reverse As String
Dim temp As Char
Dim str As Integer
str = Len(a)
For x = str To 1 Step -1
temp = Mid(a, x)
reverse = reverse + temp
Next x
Console.WriteLine(reverse)
Console.ReadKey()
End Sub
I'm still learning this language and so far it's been really fun to make small programs and stuff.
Dim TestString As String = "ABCDEFG"
Dim revString As String = StrReverse(TestString)
ref: https://msdn.microsoft.com/en-us/library/e462ax87(v=vs.90).aspx
You are getting the warning
"Warning 1 Variable 'reverse' is used before it has been assigned a
value. A null reference exception could result at runtime."
Because String variable reverse is not yet initialized. Compiler will consider the scenario that For is not executing in such situation the reverse can be null. you can get out of the warning by assigning an empty value to the string: ie.,
Dim reverse As String=String.Empty
You can do the functionality in the following ways too:
Dim inputStr As String = String.Empty
Console.WriteLine("Enter the value of the string you want to reverse: ")
inputStr = Console.ReadLine()
Dim reverse As String = String.Join("", inputStr.AsEnumerable().Reverse)
Console.WriteLine(reverse)
Console.ReadKey()
OR
Dim reverse As String = String.Join("", inputStr.ToCharArray().Reverse)
I am trying to write a program where the user inputs a telephone number and a message is displayed if it contains a letter.
Module Module1
Sub Main()
Dim TelNumber As String
Dim Character As String
TelNumber = Console.ReadLine()
For Number = 0 To TelNumber.Length - 1
Character = TelNumber.Substring(Number)
If Integer.TryParse(Character, 0) <> 0 Then
Console.WriteLine("It cannot contain a letter")
Exit For
End If
Next
Console.ReadLine()
End Sub
End Module
However with this code even it only works properly if the string contains less than 11 charcaters, after that even if it does not contain any letters it still displays the message. How do I fix this? Also I don't understand what the second parameter of the Integer.TryParse function represents?
TelNumber.Substring(Number) does not just the Numberth character of the string.
It returns the string with Number characters stripped off its beginning.
Thus, in the first step of the loop, TelNumber.Substring(0) returns the whole string.
Then, Integer.TryParse() fails with integer overflow with long string.
Hint: simple string validation is a task for regular expressions.
With regular expressions it will also be very easy to extend tel.number format to something like +4915771828000 or 12-34-56.
Imports System.Text.RegularExpressions
Module Module1
Sub Main()
Dim telNumber As String = Console.ReadLine()
Dim telValidationRegex As Regex = New Regex("^\d+$")
If NOT telValidationRegex.Match(telNumber).Success Then
Console.WriteLine("Wrong telephone number format")
End If
Console.ReadLine()
End Sub
End Module
I don't have a compiler handy, but I can tell you what I think this should look like. First let's look at Int32.TryParse's documentation
result
Type: System.Int32
When this method returns, contains the 32-bit signed integer value equivalent of the number contained in s, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null or String.Empty, is not of the correct format, or represents a number less than MinValue or greater than MaxValue. This parameter is passed uninitialized.
So, the second parameter is supposed to be an integer variable that contains the result of trying to parse the string.
Then, let's look at substring
startIndex
Type: System.Int32
The zero-based starting character position of a substring in this instance.
So what you're doing isn't looking at each character and trying to convert it to an integer. It's looking at the whole number, and trying to convert that to an integer. Then the whole number, except for the first character, and trying to convert that to a number. And so on.
I suspect you'll find that Int32 can only store numbers about 10 digits long (2^32, or 4294967296)
What you want to do is look at each character, something like this.
Module Module1
//Warning, did not try to compile
Sub Main()
Dim TelNumber As String
Dim Character As String
TelNumber = Console.ReadLine()
For Number = 0 To TelNumber.Length - 1
Character = TelNumbert(Number)
Dim OutputNumber as Integer
If Not Integer.TryParse(Character, OutputNumber) Then
Console.WriteLine("It cannot contain a letter")
Exit For
End If
Next
Console.ReadLine()
End Sub
End Module
I am taking a user input a text box and then Validating it as follows:
Val(txt_score1.text)
Then I have to compare it with blank entry in that text box. Like this:
If (Val(txt_score1.Text) = "") Then....
I am receiving a conversion error. Because "" is String whereas Val is returning Integer.
How to overcome this??
You can use Integer.TryParse to determine if the value is a proper integer:
Dim x As Integer
If Integer.TryParse(TextBox1.Text, x) Then
MessageBox.Show(x)
Else
MessageBox.Show("'" + TextBox1.Text + "' is not a valid number")
End If
If you need to just check for a blank string, you can use String.IsNullOrEmpty on the text itself:
If String.IsNullOrEmpty(TextBox1.Text) Then
MessageBox.Show("String is empty")
End If
Val is a legacy function leftover from VB6 days and has some weird behavior if you don't know about it. I avoid it for this reason. For example, take the following cases and the output they generate:
MessageBox.Show(Val("")) '0
MessageBox.Show(Val("5")) '5
MessageBox.Show(Val("5e3")) '5000
MessageBox.Show(Val("5xyz")) '5