How can I make this VB program recursive? - vb.net

I need to use recursion in this program for a school project. The program checks if the number inputted is a real number (in this case defined by a number with a decimal with the characters 0-9 (e.g. 56.7). How would I make the function recursive?
Thanks :-)
Module Real_Numbers
Sub Main()
Dim number As String
Dim check As Boolean
Console.WriteLine("Enter a number to check if it is a real number:")
number = Console.ReadLine()
check = CheckNumber(number)
If check = True Then
Console.WriteLine("The number is a real number")
Else
Console.WriteLine("The number is not a real number")
End If
Console.ReadLine()
End Sub
Function CheckNumber(ByVal number As String) As Boolean
Dim current As Char
For i As Integer = 0 To number.Length - 1
current = number.Substring(i, 1)
If current = "." Then
' Do nothing
Else
If IsNumeric(current) Then
' Do nothing
Else
Return False
End If
End If
Next
Return True
End Function
End Module

Given that this is a homework assignment, I'm not going to write the code out for you. But I will say this -- there are a couple of ways to set this up. One straightforward way would be to pass the string (of the number) to CheckNumber and then check the first character -- if it's numeric, call CheckNumber again with the remainder of the string (everything minus what you just checked). If it's not numeric, return false. You'll need a special case to handle the very last character -- if it's numeric, then return true. If you propagate the boolean response properly, your recursion should unwind itself at the end with the right answer.
Good luck!

You should call the CheckNumber function from within itself, that is a recursion. Learn more about recursion here.

Related

Visual Basic Validation

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.

how can i put check which can take first letter and rest number in textbox

I have one vb.net code where the ID text box is checking if order ID is numeric only. Now my boss want me to change this with first letter and rest numbers like(A0000000) so he needs both ways full numeric and first letter and numeric.
my existing code is.
ElseIf (Not IsNumeric(txtworkorderID.Text)) Then
invalidWorkOrderNumber = True
how can i change this to check if all are numeric or alpha numeric?
I have little bit of programming knowledge.Can someone please help me?
You could use a function like if this is what you mean? Sorry bit trouble understanding what you fully want.
Function CheckForAlphaCharacters(ByVal StringToCheck As String)
If Not Char.IsLetter(StringToCheck.Chars(0)) Then
Return False 'first character is not a letter
End If
'other check if number
For i = 1 To StringToCheck.Length - 1
If Char.IsLetter(StringToCheck.Chars(0)) Then
Return False 'characters contain a letter
End If
next
Return True 'Return true if first character is a letter and rest number
End Function
Basically this will look at the string check to see if the first character is a letter, if it isn't return false, it will then check every character after the first to make sure its not a letter.
If Regex.IsMatch(number, "^[0-9 ]+$") Then
'This will see if the whole string is all numbers! so maybe mix both this and the on above to confirm either ways acceptable?
End If
You could do this with String.Substring to pull out each part and test it both ways. For instance, something like this:
Public Function ParseId(id As String) As ParsedId
Dim number As Integer
If id?.Length > 0 Then
If Integer.TryParse(id, number) Then
Return New ParsedId() With {
.Number = number }
End If
End If
If id?.Length > 1 Then
If Char.IsLetter(id(0)) And Integer.TryParse(id.Substring(1), number) Then
Return New ParsedId() With {
.Letter = id(0),
.Number = number }
End If
End If
Return Nothing
End Function
Public Class ParsedId
Public Property Letter As String
Public Property Number As Integer
End Class
But, if there's any chance that you are going to need to make it even more flexible in the future, you may want to consider using regex (which is shorter anyway):
Public Function ParseId(id As String) As ParsedId
Dim m As Match = Regex.Match(id, "^(?<Letter>[A-Z])?(?<Number>\d+)$")
If m.Success Then
Return New ParsedId With {
.Letter = m.Groups("Letter").Value,
.Number = Integer.Parse(m.Groups("Number").Value) }
Else
Return Nothing
End If
End Function

input validation in vb 2013 input box string conversion error

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)
. . .

Validating a string

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

Why doesn't Try/Catch work within number types?

Dim mynumber as Integer 'This is the variable as an integer, (Integers only allow WHOLE numbers)
Console.WriteLine("Enter your number..") 'Ask to enter number
Try
mynumber = Console.ReadLine 'Read user input and store it
Catch
Console.WriteLine()
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Only whole numbers allowed! Press enter to start again!")
Console.ResetColor()
Console.ReadLine()
Console.Clear()
GoTo start
End Try
Okay guys, As you can see from the example above I have set up a a Try/Catch for error handling. I have come across a problem. YES the Try/Catch code prevents letters (strings) from being entered in but when I enter a decimal number it still accepts it. Why? And How can this be prevented? A decimal number is not meant to be accepted because an integer only accepts whole numbers!
Thanks.
There is an implicit conversion between numeric types and thus an error is not triggered. There are different ways to know the exact numeric type. I guess that the best option here is something on the lines of the following code:
Dim mynumber0 As Double 'This is the variable as an integer, (Integers only allow WHOLE numbers)
Dim wasOK As Boolean = True
Console.WriteLine("Enter your number..") 'Ask to enter number
Try
mynumber0 = Console.ReadLine 'Read user input and store it
If (Convert.ToInt32(mynumber0) <> mynumber0) Then
wasOK = False
End If
Catch
wasOK = False
End Try
Dim mynumber As Integer = mynumber0
If (Not wasOK) Then
Console.WriteLine()
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Only whole numbers allowed! Press enter to start again!")
Console.ResetColor()
Console.ReadLine()
Console.Clear()
GoTo start
End If
UPDATE
TryParse alternative, as suggested by mafafu
Dim mynumber As Integer 'This is the variable as an integer, (Integers only allow WHOLE numbers)
Console.WriteLine("Enter your number..") 'Ask to enter number
If (Not Integer.TryParse(Console.ReadLine, mynumber)) Then
Console.WriteLine()
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Only whole numbers allowed! Press enter to start again!")
Console.ResetColor()
Console.ReadLine()
Console.Clear()
GoTo start
End If
As has been written, you can use Integer.TryParse to check if a number can be parsed to an Integer. Also, you really should use Option Strict On, which will help Visual Studio point out problems in VB.NET code.
My take on an answer:
Option Strict On
Module Module1
Sub Main()
Dim myNumber As Integer 'This is the variable as an integer, (Integers only allow WHOLE numbers)
Dim userInput As String
Dim userInputValid As Boolean = False
While Not userInputValid
Console.Write("Enter your number.. ") 'Ask to enter number
userInput = Console.ReadLine() 'Read user input and store it
userInputValid = Integer.TryParse(userInput, myNumber)
If Not userInputValid Then
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Only whole numbers allowed! Press enter to start again!")
Console.ResetColor()
Console.ReadLine()
Console.Clear()
End If
End While
Console.WriteLine("I got the number " & myNumber.ToString())
Console.ReadLine()
End Sub
End Module
Edit: Please see the section "To set the Option Strict default setting for new projects" at Option Strict Statement.
With Option Strict Off, VB.NET tries to behave like older versions of VB which had rather loosy-goosy rules with regard to type-checking. Strings, floating-point types, and integer types could largely be used interchangeably, and trying to assign a floating-point value to an integer type would round it somehow (I forget the exact details). While there are a few very rare cases where Option Strict Off can be useful for purposes other than giving old VB6 code a chance to maybe work, only someone who is expert enough to understand the intricacies of such cases should even consider using it at all in any new code (and even then only for the very small pieces where it could be helpful).
It's important to note, by the way, that even VB.NET regards a conversion from a floating-point value to an integer type as being "successful" if rounding the floating-point value to the nearest integer would yield a value which is representable in that type, even if the floating-point value had a non-zero fractional part which got dropped during the conversion. I don't like that design (I think if one wants the Int32 nearest a given floating-point value, one should use a function that says that) but it is what it is.