DateTime.TryParseExact Doesn't Work With Single-Digit Day or Month, Regardless of Format String - vb.net

I'm trying to implement a TextBox validation for user input of dates. Long story short, I'm building a new application and the users are accustomed to entering dates this way, so I want to try and validate the input while not making them "learn" something new. I have the following event handler code I hook up to date fields to test the input:
Dim DateText As String = String.Empty
Dim ValidDates As New List(Of Date)
Dim DateFormats() As String = {"Mdyy", "Mddyy", "MMdyy", "MMddyy", "Mdyyyy", "Mddyyyy", "MMdyyyy", "MMddyyyy"}
If TypeOf sender Is System.Windows.Forms.TextBox Then
Dim CurrentField As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
If CurrentField.Text IsNot Nothing AndAlso Not String.IsNullOrEmpty(CurrentField.Text.Trim) Then
DateText = CurrentField.Text.Trim.ReplaceCharacters(CharacterType.Punctuation)
End If
For Each ValidFormat As String In DateFormats
Dim DateBuff As Date
If Date.TryParseExact(DateText, ValidFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, DateBuff) Then
If Not ValidDates.Contains(DateBuff) Then
ValidDates.Add(DateBuff)
End If
End If
Next ValidFormat
If ValidDates.Count > 1 Then
CurrentField.SelectAll()
CurrentField.HideSelection = False
MessageBox.Show("The date you entered is ambiguous." & vbCrLf & vbCrLf &
"Please enter two digits for the month, two digits for the day and" & vbCrLf &
"two digits for the year." & vbCrLf & vbCrLf &
"For example, today's date should be entered as either " & Now.ToString("MMddyy") & vbCrLf &
" or " & Now.ToString("MM/dd/yy") & ".",
"AMBIGUOUS DATE ENTERED", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
CurrentField.HideSelection = True
e.Cancel = True
ElseIf ValidDates.Count < 1 Then
CurrentField.SelectAll()
CurrentField.HideSelection = False
MessageBox.Show("The date you entered was not valid." & vbCrLf & vbCrLf &
"Please enter two digits for the month, two digits for the day and" & vbCrLf &
"two digits for the year." & vbCrLf & vbCrLf &
"For example, today's date should be entered as either " & Now.ToString("MMddyy") & vbCrLf &
" or " & Now.ToString("MM/dd/yy") & ".",
"INVALID INPUT FORMAT", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
CurrentField.HideSelection = True
e.Cancel = True
Else
CurrentField.ForeColor = SystemColors.WindowText
CurrentField.BackColor = SystemColors.Window
End If
End If
This validation method only seems to work correctly if the format includes a two-digit month and two-digit day. If I try to use any of the single-digit formats (e.g., Mddyy, MMdyyyy, etc.), TryParseExact always returns False, and the date is never added to the List(Of Date).
Here are some "hard-coded" tests I went through trying to get to the source of the problem. I've used some intentionally ambiguous dates, as well as some definitively unambiguous ones:
If Date.TryParseExact("1223", "Mdyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 1223 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (1223)")
End If
'failed (1223)
If Date.TryParseExact("12123", "Mddyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 12123 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (12123)")
End If
'failed (12123)
If Date.TryParseExact("012123", "MMddyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 012123 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (012123)")
End If
'success: 012123 -> 1/21/2023
If Date.TryParseExact("1122023", "MMdyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 1122023 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (1122023)")
End If
'failed (1122023)
If Date.TryParseExact("72521", "Mddyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 72521 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (72521)")
End If
'failed (72521)
If Date.TryParseExact("072521", "MMddyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 072521 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (072521)")
End If
'success: 072521 -> 7/25/2021
If Date.TryParseExact("3312019", "Mddyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 3312019 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (3312019)")
End If
'failed (3312019)
If Date.TryParseExact("05201975", "MMddyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 05201975 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (05201975)")
End If
'success: 05201975 -> 5/20/1975
If Date.TryParseExact("432013", "Mdyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, TempDate) Then
Console.WriteLine($"success: 432013 -> {TempDate.ToString("M/d/yyyy")}")
Else
Console.WriteLine("failed (432013)")
End If
'failed (432013)
I've seen several posts complaining of "unusual behavior" with the TryParseExact() method, but I've not been able to find anything that explains why this is actually happening. I know that I've used some of these parsing methods in the past, but I don't recall ever having this much trouble getting a simple parse to work.
I thought the whole point of using the TryParseExact() method was so that I could tell the parser specifically where the data elements were in the string and get a valid value back. Am I missing or overlooking something here?
MY "SOLUTION":
Based on the explanation from the accepted answer as well as the additional details in the accepted answer from How to convert datetime string in format MMMdyyyyhhmmtt to datetime object?, I believe I've come up with a sort of "work-around" solution that enables me to achieve my goal of allowing my users to continue doing things the way they are used to while still providing the validation I'm looking for.
Added a new List(Of String) variable where I store the possible formats for a given input string (I already limit input to numeric, -, or / only)
Added a Select Case to inject separators (/) into the string at specific positions based on the string's length
Changed the DateFormats() array to use format strings to use in TryParseExact() that include separators (/)
With this, I can test each of those values for valid dates and make my determination from there.
Here's the updated method:
Public Sub ValidateDateField(ByVal sender As Object, ByVal e As CancelEventArgs)
Dim DateText As String = String.Empty
Dim ValidDates As New List(Of Date)
Dim DateFormats() As String = {"M/d/yy", "M/dd/yy", "MM/d/yy", "MM/dd/yy", "M/d/yyyy", "M/dd/yyyy", "MM/d/yyyy", "MM/dd/yyyy"}
Dim FormattedDates As New List(Of String)
If TypeOf sender Is System.Windows.Forms.TextBox Then
Dim CurrentField As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
If CurrentField.Text IsNot Nothing AndAlso Not String.IsNullOrEmpty(CurrentField.Text.Trim) Then
'ReplaceCharacters() is a custom extension method
DateText = CurrentField.Text.Trim.ReplaceCharacters(CharacterType.Punctuation)
Select Case DateText.Length
Case < 4
CurrentField.SelectAll()
CurrentField.HideSelection = False
MessageBox.Show("The date you entered was not valid." & vbCrLf & vbCrLf &
"Please enter two digits for the month, two digits for the day and" & vbCrLf &
"two digits for the year." & vbCrLf & vbCrLf &
"For example, today's date should be entered as either " & Now.ToString("MMddyy") & vbCrLf &
" or " & Now.ToString("MM/dd/yy") & ".",
"INVALID INPUT FORMAT", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
CurrentField.HideSelection = True
e.Cancel = True
Exit Sub
Case 4
FormattedDates.Add(DateText.Insert(1, "/"c).Insert(3, "/"c))
Case 5
FormattedDates.Add(DateText.Insert(1, "/"c).Insert(4, "/"c))
FormattedDates.Add(DateText.Insert(2, "/"c).Insert(4, "/"c))
Case 6
FormattedDates.Add(DateText.Insert(1, "/"c).Insert(3, "/"c))
FormattedDates.Add(DateText.Insert(2, "/"c).Insert(5, "/"c))
Case 7
FormattedDates.Add(DateText.Insert(1, "/"c).Insert(4, "/"c))
FormattedDates.Add(DateText.Insert(2, "/"c).Insert(4, "/"c))
Case 8
FormattedDates.Add(DateText.Insert(2, "/"c).Insert(5, "/"c))
Case Else
CurrentField.SelectAll()
CurrentField.HideSelection = False
MessageBox.Show("The date you entered was not valid." & vbCrLf & vbCrLf &
"Please enter two digits for the month, two digits for the day and" & vbCrLf &
"two digits for the year." & vbCrLf & vbCrLf &
"For example, today's date should be entered as either " & Now.ToString("MMddyy") & vbCrLf &
" or " & Now.ToString("MM/dd/yy") & ".",
"INVALID INPUT FORMAT", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
CurrentField.HideSelection = True
e.Cancel = True
Exit Sub
End Select
For Each TempDate As String In FormattedDates
For Each ValidFormat As String In DateFormats
Dim DateBuff As Date
If DateTime.TryParseExact(TempDate, ValidFormat, System.Globalization.CultureInfo.CurrentCulture, DateTimeStyles.None, DateBuff) Then
If Not ValidDates.Contains(DateBuff) Then
ValidDates.Add(DateBuff)
End If
End If
Next ValidFormat
Next TempDate
If DateText.Trim.Length > 0 Then
If ValidDates.Count > 1 Then
CurrentField.SelectAll()
CurrentField.HideSelection = False
MessageBox.Show("The date you entered is ambiguous." & vbCrLf & vbCrLf &
"Please enter two digits for the month, two digits for the day and" & vbCrLf &
"two digits for the year." & vbCrLf & vbCrLf &
"For example, today's date should be entered as either " & Now.ToString("MMddyy") & vbCrLf &
" or " & Now.ToString("MM/dd/yy") & ".",
"AMBIGUOUS DATE ENTERED", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
CurrentField.HideSelection = True
e.Cancel = True
ElseIf ValidDates.Count < 1 Then
CurrentField.SelectAll()
CurrentField.HideSelection = False
MessageBox.Show("The date you entered was not valid." & vbCrLf & vbCrLf &
"Please enter two digits for the month, two digits for the day and" & vbCrLf &
"two digits for the year." & vbCrLf & vbCrLf &
"For example, today's date should be entered as either " & Now.ToString("MMddyy") & vbCrLf &
" or " & Now.ToString("MM/dd/yy") & ".",
"INVALID INPUT FORMAT", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
CurrentField.HideSelection = True
e.Cancel = True
Else
CurrentField.ForeColor = SystemColors.WindowText
CurrentField.BackColor = SystemColors.Window
End If
End If
End If
End If
End Sub

The documentation is clear about this,
If you do not use date or time separators in a custom format pattern,
use the invariant culture for the provider parameter and the widest
form of each custom format specifier. For example, if you want to
specify hours in the pattern, specify the wider form, "HH", instead of
the narrower form, "H".

Related

Skipping Current Iteration of For Loop if Condition is False

I've got a large subroutine (1958 lines) to calculate some prices and figures based on a complex decision tree.
The figures will be in one of multiple tables, so to check if there is an applicable set of data to use, I've got the following If statement
If dDt.Rows.Count = 0 And cDt.Rows.Count = 0 And p1Dt.Rows.Count = 0 And p2Dt.Rows.Count = 0 And p3Dt.Rows.Count = 0 Then
If SysAQ = False Then
Me.Cursor = Cursors.Default
MessageBox.Show("There are no rates in the system for " & cmbSupplier.Text & "/" & ugr.Cells("Product_Code").Value & "/" & cmbCustCode.Text & " for todays " & _
"date. Please add one and try again.", "No Rate Exists", MessageBoxButtons.OK, MessageBoxIcon.Information)
ugr.Cells("DSC_Code").Value = ""
ugr.Cells("DSC_Rate").Value = 0
ugr.Cells("DSC_Value").Value = 0
ugr.Cells("DSC_VAT").Value = 0
Exit Sub
ElseIf suppAQ = False Then
Me.Cursor = Cursors.Default
MessageBox.Show("There are no rates in the system for " & cmbSupplier.Text & "/" & ugr.Cells("Product_Code").Value & "/" & cmbCustCode.Text & " for todays " & _
"date. Please add one and try again.", "No Rate Exists", MessageBoxButtons.OK, MessageBoxIcon.Information)
ugr.Cells("DSC_Code").Value = ""
ugr.Cells("DSC_Rate").Value = 0
ugr.Cells("DSC_Value").Value = 0
ugr.Cells("DSC_VAT").Value = 0
Exit Sub
ElseIf aDt.Rows.Count = 0 Then
Me.Cursor = Cursors.Default
MessageBox.Show("There are no rates in the system for " & cmbSupplier.Text & "/" & ugr.Cells("Product_Code").Value & "/" & cmbCustCode.Text & " for todays " & _
"date. Please add one and try again.", "No Rate Exists", MessageBoxButtons.OK, MessageBoxIcon.Information)
ugr.Cells("DSC_Code").Value = ""
ugr.Cells("DSC_Rate").Value = 0
ugr.Cells("DSC_Value").Value = 0
ugr.Cells("DSC_VAT").Value = 0
Exit Sub
End If
End If
This block of code is within a For Loop, For Each ugr As UltraGridRow in ugLines.Rows
This means it's checking if there is a price for the product on the line, and if not, alerts the user and exits the subroutine.
This subroutine is called on ugLines.AfterRowInsert, (Once a product has been added), as well as before saving the full data.
It works fine for the latter scenario, as whenever it detects a line with no price, it will error and not save. However, if a product has been added with no price, then the user adds another product, it will never add the price in or tell the user the new line is missing a price as the first one always fails.
What I'm wondering, is if there is another way to set this out? Instead of having Exit Sub, can I change it to skip the rest of the code and jump straight to the next iteration? I've looked at using Continue and Continue For, but that seems to be only applicable if checking the opposite, to check where each product does have a price in at least one of the tables, making the If Statement more complex - Is there another way around this?
Essentially, just changing the code in your question to the following:
Dim noRatesInSystem As Boolean = False
If dDt.Rows.Count = 0 And cDt.Rows.Count = 0 And p1Dt.Rows.Count = 0 And p2Dt.Rows.Count = 0 And p3Dt.Rows.Count = 0 Then
If SysAQ = False OrElse suppAQ = False OrElse aDt.Rows.Count = 0 Then
Me.Cursor = Cursors.Default
MessageBox.Show("There are no rates in the system for " & cmbSupplier.Text & "/" & ugr.Cells("Product_Code").Value & "/" & cmbCustCode.Text & " for todays " & _
"date. Please add one and try again.", "No Rate Exists", MessageBoxButtons.OK, MessageBoxIcon.Information)
ugr.Cells("DSC_Code").Value = ""
ugr.Cells("DSC_Rate").Value = 0
ugr.Cells("DSC_Value").Value = 0
ugr.Cells("DSC_VAT").Value = 0
noRatesInSystem = True
End If
End If
If noRatesInSystem = True Then Continue For
This will A) Tidy up the If Statement, B) Continue the loop if a price is found and C) Skip the iteration (Jump to Next) if there are no prices found.

This date time literal was not understood

I get an error saying "This date time literal was not understood" with this formula:
Private Sub btnOPrint_Click(sender As Object, e As EventArgs) Handles btnOPrint.Click
If MsgBox("Print Offertory Record?", MsgBoxStyle.OkCancel, "Print Record") = MsgBoxResult.Ok Then
Dim report As New ReportDocument
report.Load("C:\Users\Paolo\Documents\Visual Studio 2015\Projects\NewMonitoringSystem\NewMonitoringSystem\OffertoryReport.rpt")
docprint.CrystalReportViewer1.ReportSource = report
docprint.CrystalReportViewer1.SelectionFormula = "{tblOffertory.Date}=""" & dtpOffertory.Text & """ AND {tblOffertory.Weekly}=#" & txtOffertory.Text & "#"
docprint.CrystalReportViewer1.Refresh()
docprint.Show()
End If
End Sub
If I remove this line...
AND {tblOffertory.Weekly}=#" & txtOffertory.Text & "#"
...and instead use this line...
docprint.CrystalReportViewer1.SelectionFormula = "{tblOffertory.Date}=""" & dtpOffertory.Text & """"
...it shows the report with no data, just the columns. What formula should I use?

Why is skipping the else part of my code?

'REQUIREMENTS:Write a Visual Basic procedure called CalculateTotalCost that reads user-entered data from the txtQuantity and txtUnitCost TextBox controls. The CalculateTotalCost procedure should convert the text entered in the two TextBox controls into numbers. It should then multiple the two numbers together, apply the appropriate discount based on the quantity ordered, and display the result in the lblTotalCost Label control.
The following error-checking rules apply:
a. The text entered by the user in the txtQuantity TextBox control must represent a non-negative Integer. If it does not, the procedure should output the phrase “Invalid quantity!” in the lblTotalCost Label control and no further processing should take place.
b. The text entered by the user in the txtUnitCost TextBox control must represent a non-negative Double. If it does not, the procedure should output the phrase “Invalid unit cost!” in the lblTotalCost Label control and no further processing should take place.
Assuming no user input errors, the properly discounted total presented in the lblTotalCost Label control should be displayed in currently format. The display should contain a leading currency symbol (depending on how the computer was set up, this will probably be a dollar sign) and exactly two trailing digits after the included decimal point.
Public Class Form1
Private Sub lblTotalCost_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblTotalCost.Click
'Author: Eric Konga_ 14200694 _BCIT/3_ The Papaua New Guinea University of Technology
' this program will read read user entered data from the two text boxes on the form and
' will calcualte (Multiply) the two numbers together and will then apply the appropriate discount
'based on the quantity ordered, and display the result(Total Cost) in the Label control.
'Declaring Variables as strings. This sets will out put to the screen the appropriate percentages
'based the quantity ordered.
Dim strDiscount As String
Dim strDiscount1 As String
Dim strDiscount2 As String
Dim strDiscount3 As String
Dim strDiscount4 As String
'declaring variables as integer, double and long. this sets of program will output to the screen
'
Dim intQuantity As Integer
Dim dblUnitCost As Double
Dim dblTotalCost As Double
'Assigning Variables
strDiscount = "0%"
strDiscount1 = "20%"
strDiscount2 = "30%"
strDiscount3 = "40%"
strDiscount4 = "50%"
' This is a mathematical calculator that calculates the TotalCost (TC).
intQuantity = txtQuantity.Text
dblUnitCost = txtUnitCost.Text
dblTotalCost = intQuantity * dblUnitCost
If intQuantity <= 9 Then
lblTotalCost.Text = "The Total Cost is: $" & String.Format("{0:n2}", dblTotalCost) & " and it's " & strDiscount & _
" Discount."
ElseIf intQuantity <= 19 Then
lblTotalCost.Text = "The Total Cost is: $" & String.Format("{0:n2}", dblTotalCost) & " and it's " & strDiscount1 & _
" Discount."
ElseIf intQuantity <= 49 Then
lblTotalCost.Text = "The Total Cost is: $" & String.Format("{0:n2}", dblTotalCost) & " and it's " & strDiscount2 & _
" Discount."
ElseIf intQuantity <= 99 Then
lblTotalCost.Text = "The Total Cost is: $" & String.Format("{0:n2}", dblTotalCost) & " and it's " & strDiscount3 & _
" Discount."
ElseIf intQuantity >= 100 Then
lblTotalCost.Text = "The Total Cost is: $" & String.Format("{0:n2}", dblTotalCost) & " and it's " & strDiscount4 & _
" Discount."
' under this condition, it will only execute if the integer(QTY) is negative or
'the unser entered float(UC) is negative.
Else
lblTotalCost.Text = (" Invalid Quantity!" & " or Ivalid Unit Cost!")
End If
End Sub
End Class
Because your first if condition is <= 9. This includes all negative integers.

Vb.net Journal Program Issue

Okay so for an internship project i'm making a Journal with streamwriters and streamreaders.
I have to to where you can create an account with a name, Username, and Password. I also have it to where it creates a txt file in that persons name when you create the account. Now, they login and it brings them to the journal page. The Journal Page for the most part has a Date for your journal Entry, the title of the journal and the journal entry text itself.
The problem that I am having is that when you click the button to create/edit a journal entry, it goes through a sub routine that checks if that journal exists (Meaning that there is already one for that date) or not. If it doesn't exist, then it should create a new one at the bottom of the text file. If it does exist then it should edit the lines in which that journal are stationed in the text file.
Code:
Private Sub CreateBtn_Click(sender As System.Object, e As System.EventArgs) Handles CreateBtn.Click
Errors = ""
Dim TempCounter As Integer = 0
If TitleTxt.Text = "" Then
Errors = "You must enter a title." & vbCrLf
End If
If JournalTextRtxt.Text = "" Then
Errors &= "You must enter an entry for the journal."
End If
If Errors <> "" Then
MessageBox.Show("There's an error in creating/editing your journal." & vbCrLf & "Error(s):" & vbCrLf & Errors, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
JournalDate = DateTimePicker1.Value
JournalTitle = TitleTxt.Text
JournalText = JournalTextRtxt.Text
arrJournalEntries(TempCounter).TheDate = JournalDate
arrJournalEntries(TempCounter).Title = JournalTitle
arrJournalEntries(TempCounter).JournalEntry = JournalText
CheckAndWrite()
End If
End Sub
Private Sub CheckAndWrite()
Dim Reader As New StreamReader(MyName & ".txt", False)
Dim Sline As String = Reader.ReadLine
Counter = 0
Do Until (Sline Is Nothing) 'Perform the code until the line in the text file is blank
If Not Sline Is Nothing Then 'If the line in the text file is NOT blank then
For i As Integer = 1 To 3
Select Case i
Case 1
arrJournalEntries(Counter).TheDate = Sline
Sline = Reader.ReadLine
Case 2
arrJournalEntries(Counter).Title = Sline
Sline = Reader.ReadLine
Case 3
arrJournalEntries(Counter).JournalEntry = Sline
Sline = Reader.ReadLine
End Select
Next
End If
JournalDate = arrJournalEntries(Counter).TheDate
Time = DateTimePicker1.Value
MsgBox("Journal Date = " & JournalDate & vbCrLf & "Today's Date = " & Time)
If Time = JournalDate Then
JournalFound = True
Else
Counter += 1
JournalFound = False
End If
Loop
Reader.Close()
Try
If Sline Is Nothing Or JournalFound = False Then
MsgBox("Your journal is now going to be created.")
JournalDate = DateTimePicker1.Value
JournalTitle = TitleTxt.Text
JournalText = JournalTextRtxt.Text
arrJournalEntries(Counter).TheDate = JournalDate
arrJournalEntries(Counter).Title = JournalTitle
arrJournalEntries(Counter).JournalEntry = JournalText
Dim Writer As New StreamWriter(MyName & ".txt", True)
Do Until (arrJournalEntries(Counter).TheDate = Nothing)
Writer.WriteLine(arrJournalEntries(Counter).TheDate)
Writer.WriteLine(arrJournalEntries(Counter).Title)
Writer.WriteLine(arrJournalEntries(Counter).JournalEntry)
Counter += 1
Loop
Writer.Close()
End If
If JournalFound = True Then
MsgBox("Your journal is now going to be edited.")
JournalDate = DateTimePicker1.Value
JournalTitle = TitleTxt.Text
JournalText = JournalTextRtxt.Text
arrJournalEntries(Counter).TheDate = JournalDate
arrJournalEntries(Counter).Title = JournalTitle
arrJournalEntries(Counter).JournalEntry = JournalText
Dim Writer As New StreamWriter(MyName & ".txt", True)
Do Until (arrJournalEntries(Counter).TheDate = Nothing)
Writer.WriteLine(arrJournalEntries(Counter).TheDate)
Writer.WriteLine(arrJournalEntries(Counter).Title)
Writer.WriteLine(arrJournalEntries(Counter).JournalEntry)
Counter += 1
Loop
Writer.Close()
End If
Catch ex As Exception
MessageBox.Show("An error has occured" & vbCrLf & vbCrLf & "Original Error:" & vbCrLf & ex.ToString)
End Try
End Sub`
The problem that's occuring is that it's not only writing in the first time wrong. When it's supposed to say it's going to edit, it doesn't, it just says creating. But it just adds on to the file. After pressing the button 3 times with the current date. and the Title being "Test title", and the journal entry text being "Test text". This is what occured.
It should just be
7/10/2012 3:52:08 PM
Test title
Test text
7/10/2012 3:52:08 PM
Test title
Test text
the whole way through. but of course if it's the same date then it just overwrites it. So can anybody please help me?
You are only filtering your array by the date, so it looks like you have an object with a date but no title or text:
Do Until (arrJournalEntries(Counter).TheDate = Nothing)
The "quick" fix:
Do Until (arrJournalEntries(Counter).TheDate = Nothing)
If arrJournalEntries(Counter).Title <> String.Empty Then
Writer.WriteLine(arrJournalEntries(Counter).TheDate)
Writer.WriteLine(arrJournalEntries(Counter).Title)
Writer.WriteLine(arrJournalEntries(Counter).JournalEntry)
End If
Counter += 1
Loop
Do consider getting rid of the array and using a List(of JournalEntry) instead. Your code looks difficult to maintain in its current state.

VB.Net Regex Help

I've got 3 or 4 patterns that I'm comparing user input against and I need to figure out if the user input matches one of the patters and to return the match if it does.
Since the input is multiline, I'm passing each individual line like so:
Dim strRawInput() As String = Split(txtInput.Text, vbCrLf)
Dim strInput As String
txtOutput.Text = ""
For Each strInput In strRawInput
strInput.Trim(vbCr, vbLf, Chr(32))
Validation(strInput)
Next
Then I have this to find matches:
Dim m As Match
For i = 0 To strValidator.Length - 1
Dim r As New Regex(strValidator(i))
m = r.Match(strInput)
If m.Success Then
txtOutput.Text = txtOutput.Text & "Success: " & m.ToString & vbCrLf
Exit Sub
Else
End If
Next
txtOutput.Text = txtOutput.Text & "Not this time" & vbCrLf
How can I do this more efficiently? Also, I added the Exit Sub there to avoid showing the "Not this time" message even after a match is found (if the match is with one of the later patterns in the array), but I'd like to find a better way of doing that too.
Thanks in advance.
Rather than generating your Regexs in the loop, generate them one time at the startup of the application. So maybe something like:
Private Shared m_regexes As New List(Of Regex)
Shared Sub New()
For Each v As String In strValidator
m_regexes.Add(New Regex(v))
Next
End Sub
And then you can change your other code to:
For Each r As Regex In m_regexes
Dim m As Match = r.Match(strInput)
If m.Success Then
txtOutput.Text = txtOutput.Text & "Success: " & m.ToString & vbCrLf
Exit Sub
Else
End If
Next
Regarding the Exit Sub, I think it's fine, You've discovered that it matches at least one pattern, so why continue to evaluate the rest. But if you don't like methods that can "return" in multiple places, you could just replace it with a Boolean and a Exit For as:
Dim found as Boolean = false
For Each ...
If IsMatch Then
found = True
Exit For
End If
Next
If Found Then
....
Else
.....
End If
Hmm if that's the case then wouldn't this be even better?
For i = 0 To strValidator.Length - 1
Dim r As New Regex(strValidator(i))
Dim m As Match = r.Match(strInput)
If m.Success Then
txtOutput.Text = txtOutput.Text & "Success: " & m.ToString & vbCrLf
Exit Sub
End If
Next