Can a range of negative and positive numbers be used to pattern match using Like in vb.net - vb.net

I have a user entered string:
"{0.3064, 15.6497, 60.7668, 52.1362, 76.6645, 97, -15.8315, -6.8806, 5.547, -2.3381, -23.9905, 40.4569, 60.1592, 27.1418, 42.9375, -22.8297, -11.7423, -17.1576, -33.9918, 7.0585}"
and I would like to be able to validate it based on having a "{" at the start, a "}" at the end and twenty comma separated numbers between -1000 and 1000 in between the commas.
I have tried using the like operator as below with no luck. Everything returns False no matter whether it matches the patter or not. How can I validate based on this pattern.
This is what I have tried:
ArrayOk = ArrayValues1txt.Text Like "{[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000],[(1000)-1000]}"
If ArrayOk = False Then
MsgBox("Wrong array pattern! Pattern must contain 20 elements and be in the form {#,#}",
MessageBoxButtons.OK, "Bad Array Entered")
GoTo Canceller
Else
End If

You can use RegEx to validate the general pattern of: Are there 20 decimal values separated by commas wrapped in curly brackets?
Dim pattern = "^{((-?\d+(\.\d+)?),\s?){19}(-?\d+(\.\d+)?)}$"
Dim input = "{0.3064, 15.6497, 60.7668, 52.1362, 76.6645, 97, -15.8315, -6.8806, 5.547, -2.3381, -23.9905, 40.4569, 60.1592, 27.1418, 42.9375, -22.8297, -11.7423, -17.1576, -33.9918, 7.0585}"
If (Regex.IsMatch(input, pattern)) Then
End If
Once you validated that it matches the specific pattern, you can validate that the numbers match the numeric range validation by doing the following:
Remove the brackets from the String
Split the string by a comma
Trim any excessive whitespace from the items
Convert the items to fractional values (Double, Decimal, etc.)
Check if the items are within range
You can do a lot of those steps using LINQ which would make it much more concise:
Dim pattern = "^{((-?\d+(\.\d+)?),\s?){19}(-?\d+(\.\d+)?)}$"
Dim input = "{0.3064, 15.6497, 60.7668, 52.1362, 76.6645, 97, -15.8315, -6.8806, 5.547, -2.3381, -23.9905, 40.4569, 60.1592, 27.1418, 42.9375, -22.8297, -11.7423, -17.1576, -33.9918, 7.0585}"
If (Regex.IsMatch(input, pattern)) Then
input = input.Replace("{", String.Empty).Replace("}", String.Empty)
Dim items = input.Split(",")
Dim convertedItems = items.Select(Function(item) Convert.ToDouble(item.Trim())).ToArray()
If (convertedItems.All(Function(item) item >= -1000 AndAlso item <= 1000)) Then
Console.WriteLine("All of the items are within -1000 and 1000")
End If
End If
Here is a live demo: fiddle

I used String.StartsWith and String.EndsWith to test for the braces. Next I chopped them off with Substring. I then split the string by commas. I checked whether there were exactly 20 elements.
If we get this far, I loop through each element. Trim off any leading or trailing spaces and change it to a double. Then I can do the number comparison.
Private Function ValidateArray(input As String) As Boolean
If Not input.StartsWith("{") OrElse Not input.EndsWith("}") Then
Return False
End If
input = input.Substring(1, input.Length - 2)
Dim splits = input.Split(","c)
If splits.Length <> 20 Then
Return False
End If
For Each n In splits
Dim dbl = CDbl(n.Trim)
If dbl > 1000 OrElse dbl < -1000 Then
Return False
End If
Next
Return True
End Function
Usage:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim IsValid = ValidateArray("{0.3064, 15.6497, 60.7668, 52.1362, 76.6645, 97, -15.8315, -6.8806, 5.547, -2.3381, -23.9905, 40.4569, 60.1592, 27.1418, 42.9375, -22.8297, -11.7423, -17.1576, -33.9918, 7.0585}")
MessageBox.Show(IsValid.ToString)
End Sub

Related

Math expression parsing: incorrect output when a + followed by a -

I am trying to create a program that parses an expression such as 3x^3 + 7x^2 + 6x - 9. I am using a recursive system to do this. At the moment, I'm just testing to see if I get the correct output for the expression I input by only using constants in the expression. The code works fine with most expressions, but when I have a minus followed by a positive, both terms are subtracted (first term should be subtracted, second term should be added). An example of this is entering 4*3^2-7*3+5*3. The answer to this is 30 but the program does 4*3^2-7*3-5*3 instead and outputs 0. I am unsure how to solve this.
Code:
Private Function ParseExpr(ByRef expression As String)
Dim op, op1 As Integer
op = ParseFactor(expression)
If expression.Length <> 0 Then
If (expression(0) = "+") Then
expression = expression.Substring(1, expression.Length - 1)
op1 = ParseExpr(expression)
op += op1
ElseIf (expression(0) = "-") Then
expression = expression.Substring(1, expression.Length - 1)
op1 = ParseExpr(expression)
op -= op1
End If
End If
Return op
End Function
All is well with raising to a power and multiplication. At that point we are simplified to 36-21+15. Here we must remember that we are adding -21. So we need to go back to -7 . When I build my list of numbers (it handles numbers of more than one digit) I add the minus sign to the number it precedes.
This code does not handle decimal numbers or parenthesis. I think you will be able to add the division operator, if you wish.
Private NumList As New List(Of Double)
Private OperatorList As New List(Of String)
Private Sub OpCode()
Dim Input = "14*3^2-7*3+15*3"
PopulateLists(Input)
Dim OpIndex As Integer
Dim NewNum As Double
Dim operators = {"^", "*", "+"} 'Note: no minus sign, the minus goes with the number
For Each op In operators
Do
OpIndex = OperatorList.IndexOf(op)
If OpIndex = -1 Then
Exit Do
End If
Select Case op
Case "^"
NewNum = NumList(OpIndex) ^ NumList(OpIndex + 1)
Case "*"
NewNum = NumList(OpIndex) * NumList(OpIndex + 1)
Case "+"
NewNum = NumList(OpIndex) + NumList(OpIndex + 1)
End Select
NumList.RemoveAt(OpIndex + 1)
NumList(OpIndex) = NewNum
OperatorList.RemoveAt(OpIndex)
Loop
Next
MessageBox.Show(NumList(0).ToString) 'Displays 150
End Sub
Private Sub PopulateLists(Input As String)
Dim strNum As String = ""
For Each c As Char In Input 'Be careful here, the IDE wants to add () at the end of this line - it doesn't belong
If Char.IsDigit(c) Then
strNum &= c
ElseIf c = "-" Then
OperatorList.Add("+") 'We are adding a negative number
NumList.Add(CDbl(strNum)) 'Add the last number we accumulated so we can start a new one with the minus sign
strNum = "-" 'Start a new number with the minus sign
Else 'The other operators are added to the list
OperatorList.Add(c)
NumList.Add(CDbl(strNum))
strNum = ""
End If
Next
NumList.Add(CInt(strNum)) 'The last number which will not be followed by an operator
End Sub

VB windows form calculate the digit in a multiline textbox

I want to calculate each line: it's like first line 123*1.616 and the second line 213*1.616, and display each total.
Every number entred in the kilogram textbox will mutiply 1.616 and then show the result in the kati label.
Here is my code:
Private Sub b1_Click(sender As Object, e As EventArgs) Handles b1.Enter
For Each digit In (TextBox1.Text)
total1 = Val(digit) * 1.616
Label9.Text = total1
Next
Label9.Text = total1
End sub
Please help me find some solution or explanation to achieve the output.
This should work
Private FACTOR As Decimal = 1.616
Private SEPARATOR As String = Environment.NewLine
Private Sub b1_Click(sender As Object, e As EventArgs) Handles b1.Click
Label9.Text = TextBox1.Text.
Split({SEPARATOR}, StringSplitOptions.RemoveEmptyEntries).
Select(Function(s1) $"{Decimal.Parse(s1) * FACTOR:0.00#}").
Aggregate(Function(s1, s2) $"{s1}{SEPARATOR}{s2}")
End Sub
Here are the functions in the LINQ
Split makes an array out of each line in the TextBox using SEPARATOR as the delimiter
Select transforms the elements into their value times FACTOR
Aggregate puts the elements back together into a SEPERATOR delimited string
Why didn't your original code work?
You were iterating over each char in the text, and multiplying the char by a float (Option Strict On, as suggested in the comments would have prevented that).
Then in each iteration, you do (simplified) Label9.Text = Val(digit) * 1.616 which overwrites the Label every time.
If you were to step through in debug (also suggested in comments), you would see the Label becoming 1x1.616=1.616, 2x1.616=3.232, 3x1.616=4.848, etc. The result was the very last character in your TextBox, '3', times 1.161 = 4.848. Obviously, this was not what you wanted. You needed to instead iterate over each entire number. The multiline TextBox separates each line with a new line. So we iterate over each line instead.
you can use split string by vbCrLf
Sub main()
Dim multilinetext As String =
"10
20
30
40
50
60"
Dim number_array = multilinetext.Split(vbCrLf)
Dim output As Integer = 0
For Each i In number_array
output += i
Next
Stop
End Sub

Visual basic palindrome code

I am trying to create an application which will determine whether a string entered by user is a palindrome or not.
Is it possible to do without StrReverse, possibly with for next loop. That's what i have done so far.
Working one, with StrReverse:
Dim userInput As String = Me.txtbx1.Text.Trim.Replace(" ", "")
Dim toBeComparedWith As String = StrReverse(userInput)
Select Case String.Compare(userInput, toBeComparedWith, True)
Case 0
Me.lbl2.Text = "The following string is a palindrom"
Case Else
Me.lbl2.Text = "The following string is not a palindrom"
End Select
Not working one:
Dim input As String = TextBox1.Text.Trim.Replace(" ", "")
Dim pallindromeChecker As String = input
Dim output As String
For counter As Integer = input To pallindromeChecker Step -1
output = pallindromeChecker
Next counter
output = pallindromeChecker
If output = input Then
Me.Label1.Text = "output"
Else
Me.Label1.Text = "hi"
End If
While using string reversal works, it is suboptimal because you're iterating over the string at least 2 full times (as string reversal creates a copy of a string because strings are immutable in .NET) (plus extra iterations for your Trim and Replace calls).
However consider the essential properties of a palindrome: the first half of a string is equal to the second half of the string in reverse.
The optimal algorithm for checking a palindrome needs only iterate through half of the input string - by comparing value[n] with value[length-n] for n = 0 to length/2.
In VB.NET:
Public Shared Function IsPalindrome(value As String) As Boolean
' Input validation.
If value Is Nothing Then Throw New ArgumentNullException("value")
value = value.Replace(" ", "") // Note String.Replace(String,String) runs in O(n) time and if replacement is necessary then O(n) space.
' Shortcut case if the input string is empty.
If value.Length = 0 Then Return False ' or True, depends on your preference
' Only need to iterate until half of the string length.
' Note that integer division results in a truncated value, e.g. (5 / 2 = 2)...
'... so this ignores the middle character if the string is an odd-number of characters long.
Dim max As Integer = value.Length - 1
For i As Integer = 0 To value.Length / 2
If value(i) <> value(max-i) Then
' Shortcut: we can abort on the first mismatched character we encounter, no need to check further.
Return False
End If
Next i
' All "opposite" characters are equal, so return True.
Return True
End Function

vb.net string contains only 4 digit numbers(or a year)

how can i check if a string only contains 4 digit numbers ( or a year )
i tried this
Dim rgx As New Regex("^/d{4}")
Dim number As String = "0000"
Console.WriteLine(rgx.IsMatch(number)) // true
number = "000a"
Console.WriteLine(rgx.IsMatch(number)) // false
number = "000"
Console.WriteLine(rgx.IsMatch(number)) //false
number = "00000"
Console.WriteLine(rgx.IsMatch(number)) // true <<< :(
this returns false when its less than 4 or at characters but not at more than 4
thanks!
I actually wouldn't use a regex for this. The expression is deceptively simple (^\d{4}$), until you realize that you also need to evaluate that numeric value to determine a valid year range... unless you want years like 0013 or 9015. You're most likely going to want the value as an integer in the end, anyway. Given that, the best validation is probably just to actually try to convert it to an integer right off the bat:
Dim numbers() As String = {"0000", "000a", "000", "00000"}
For Each number As String In numbers
Dim n As Integer
If Integer.TryParse(number, n) AndAlso number.Length = 4 Then
'It's a number. Now look at other criteria
End If
Next
Use LINQ to check if All characters IsDigit:
Dim result As Boolean = ((Not number Is Nothing) AndAlso ((number.Length = 4) AndAlso number.All(Function(c) Char.IsDigit(c))))
You should use the .NET string manipulation functions.
Firstly the requirements, the string must:
Contain exactly four characters, no more, no less;
Must consist of a numeric value
However your aim is to validate a Date:
Function isKnownGoodDate(ByVal input As String) As Boolean 'Define the function and its return value.
Try 'Try..Catch statement (error handling). Means an input with a space (for example ` ` won't cause a crash)
If (IsNumeric(input)) Then 'Checks if the input is a number
If (input.Length = 4) Then
Dim MyDate As String = "#01/01/" + input + "#"
If (IsDate(MyDate)) Then
Return True
End If
End If
End If
Catch
Return False
End Try
End Function
You may experience a warning:
Function isKnownGoodDate does not return a value on all code
paths. Are you missing a Return statement?
this can be safely ignored.

How to I count the number of zeros in string until i come across a non zero vb.net

Examples
IF the user enters a 00001 the count would be 4
If the user enters a 0811 the count would be 1
How would i do this?
The most efficient way is to simply loop through the characters of the string and count each character that is a 0 until your read a non 0 character.
I do not use VB.NET much, so this is just some rough VBish pseudo code
Dim myString As String = "00001"
Dim count As Integer = 0
For Each c As Char In myString
If C = "0"c Then
count += 1
Else
Exit For
End If
Next
And here is the one line answer without a visible for loop.
Module Module1
Sub Main()
Console.WriteLine(GetLeadingZeros("00001"))
Console.WriteLine(GetLeadingZeros("0889"))
Console.WriteLine(GetLeadingZeros("1"))
Console.WriteLine(GetLeadingZeros("00101"))
Console.WriteLine(GetLeadingZeros("11111"))
Console.WriteLine(GetLeadingZeros("10001"))
Console.ReadLine()
End Sub
Public Function GetLeadingZeros(ByVal input As String) As String
Return input.Substring(0, input.IndexOf(input.SkipWhile(Function(e) e = "0")(0)))
End Function
End Module