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