Android Question Regular expression for date

Sergey_New

Well-Known Member
Licensed User
Longtime User
I made a pattern for the date in the format "dd MMM yyyy", for example 11 Jun 2025:
B4X:
^([0-9]?|[0-2][0-9]||3[0-1])\s(\S+)\s(\d+)$
Please help me improve it so that if the day, month, year value is missing, the remaining data in each group is determined.
 

John Naylor

Active Member
Licensed User
Longtime User
Everything is OK.
Tell me why this is:
B4X:
Dim lc As String = t.ToLowerCase
Because month names should only be like this:
B4X:
monthNames.AddAll(Array As String("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"))
If the name is incorrect, there should be an error message.
If possible, please correct your code.
So you want an error if "jun" is passed? Or "aPr"? as examples?

My way the sub just deals with month names with incorrect case.

To make sure it returns a 3 letter month with the first letter capitalized simply change the code a little.


B4X:
        ' month name/abbr?
        Else If monthNames.IndexOf(lc) > -1 Then
            t = t.SubString2(0,1).ToUpperCase & t.SubString (1).ToLowerCase
            rMap.Put("Month", t)
        End If

Now, passing s = "11 jun 2025" will return 11, Jun, 2025 respectively
 
Last edited:
Upvote 0

Sergey_New

Well-Known Member
Licensed User
Longtime User
I need that if the month name does not match the required one, there should be an error about the invalid month format.
 
Upvote 0

John Naylor

Active Member
Licensed User
Longtime User
I need that if the month name does not match the required one, there should be an error about the invalid month format.
The month format would be correct. Just the case of the letters would be wrong. This fixes it for you without you having to deal with an error. When you compare them elsewhere just use .toupper so you are comparing like for like.

If the name of the month is actually wrong then


B4X:
        ' month name/abbr?
        Else If monthNames.IndexOf(lc) > -1 Then
            t = t.SubString2(0,1).ToUpperCase & t.SubString (1).ToLowerCase
            rMap.Put("Month", t)
        Else
            If lc.Length > 0 Then
                rMap.Put ("Month", "ERROR")
            End If
        End If
 
Last edited:
Upvote 0

Sergey_New

Well-Known Member
Licensed User
Longtime User
Works as required. Can I remove long month names from monthNames? I removed them and everything works.
 
Upvote 0

emexes

Expert
Licensed User
Longtime User
Because month names should only be like this

Ripper, that exact casing and length makes things easier. Try this Sub:

B4X:
Sub ParseDate(D As String) As Map
    Dim Pattern As String = "^(\d{1,2}|)\D?(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|)\D?(\d{4}|)$"

    Dim m As Matcher = Regex.Matcher(Pattern, D)
   
    If m.Find Then
        If m.GroupCount = 3 Then
            Return CreateMap("Day":m.Group(1), "Month":m.Group(2), "Year":m.Group(3))  
        End If
    End If
   
    Return CreateMap()    'or whatever represents invalid date format error
End Sub

and test with these:

B4X:
Log(ParseDate("20 Jul 1969"))
Log(ParseDate("20 Jul"))
Log(ParseDate("20 1969"))
Log(ParseDate("20"))
Log(ParseDate("Jul 1969"))
Log(ParseDate("Jul"))
Log(ParseDate("1969"))
Log(ParseDate(""))
Log(ParseDate("6 Jan 2021"))
Log(ParseDate("6 Jan"))
Log(ParseDate("6 2021"))
Log(ParseDate("6"))
Log(ParseDate("Jan 2021"))
Log(ParseDate("Jan"))
Log(ParseDate("2021"))
Log(ParseDate(""))
Log(ParseDate("04 Oct 1957"))
Log(ParseDate("04 Okt 1957"))
Log(ParseDate("is not date"))

should give this:

Log output:
Hello world!!!
(MyMap) {Day=20, Month=Jul, Year=1969}
(MyMap) {Day=20, Month=Jul, Year=}
(MyMap) {Day=20, Month=, Year=1969}
(MyMap) {Day=20, Month=, Year=}
(MyMap) {Day=, Month=Jul, Year=1969}
(MyMap) {Day=, Month=Jul, Year=}
(MyMap) {Day=, Month=, Year=1969}
(MyMap) {Day=, Month=, Year=}
(MyMap) {Day=6, Month=Jan, Year=2021}
(MyMap) {Day=6, Month=Jan, Year=}
(MyMap) {Day=6, Month=, Year=2021}
(MyMap) {Day=6, Month=, Year=}
(MyMap) {Day=, Month=Jan, Year=2021}
(MyMap) {Day=, Month=Jan, Year=}
(MyMap) {Day=, Month=, Year=2021}
(MyMap) {Day=, Month=, Year=}
(MyMap) {Day=04, Month=Oct, Year=1957}
(MyMap) {}
(MyMap) {}

but tbh the @John Naylor solution is easier to understand and thus probably handles deceptive cases better

edit: I present this alternative to align with your original post about doing it with (only?) regex 🍻
 
Upvote 0

Sergey_New

Well-Known Member
Licensed User
Longtime User
emexes, thanks for this solution!
Only m.GroupCount is always 3, no need to check it :)
I have attached an example.
 

Attachments

  • test2.zip
    2.4 KB · Views: 68
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
?
regular expression that optionally captures
always returns 3 groups day, month and year

B4X:
Private Sub Button1_Click
    Log ("Day- " & ParseDate ("11"))
    Log ("Year - " & ParseDate ("2025"))
    Log ("Month - " & ParseDate ("Jun"))
    Log ("Day and Month - " & ParseDate ("11 Jun"))
    Log ("Day and Month and Year - " & ParseDate ("11 Jun 2025"))
    Log ("None - " & ParseDate (" "))
End Sub

Sub ParseDate(Input As String) As Map
    Dim Pattern As String = $"^(\d{1,2})? ?([A-Za-z]{3})? ?(\d{4})?$"$
    Dim Result As Map :    Result.Initialize
 
    Dim Matcher1 As Matcher = Regex.Matcher(Pattern, Input.Trim)
    If Not (Matcher1.Find) Then Return Result

    Result.Put ("Day",     IIf(Matcher1.Group(1) = Null, "", Matcher1.Group(1)))
    Result.Put ("Month", IIf(Matcher1.Group(2) = Null, "", Matcher1.Group(2)))
    Result.Put ("Year",  IIf(Matcher1.Group(3) = Null, "", Matcher1.Group(3)))

    Return Result
End Sub
1749712180762.png



Note:
does not validate whether the month name is correct. You can add additional validations if you wish.
 

Attachments

  • regex.zip
    2.9 KB · Views: 61
Last edited:
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
other: valid day 1 to 31 and month
B4X:
Sub ParseDate(Input As String) As Map
'    Dim Pattern As String = $"^(\d{1,2})? ?([A-Za-z]{3})? ?(\d{4})?$"$
'    Dim Pattern As String = $"^(?i)(\d{1,2})? ?(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)? ?(\d{4})?$"$ 'valid month
    Dim Pattern As String = $"^(?i)(0?[1-9]|[12][0-9]|3[01])? ?(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)? ?(\d{4})?$"$ 'valid day 1 to 31
    Dim Result As Map :    Result.Initialize
 
    Dim Matcher1 As Matcher = Regex.Matcher(Pattern, Input.Trim)
    If Not (Matcher1.Find) Then Return Result

    Result.Put ("Day",     IIf(Matcher1.Group(1) = Null, "", Matcher1.Group(1)))
    Result.Put ("Month", IIf(Matcher1.Group(2) = Null, "", Matcher1.Group(2)))
    Result.Put ("Year",  IIf(Matcher1.Group(3) = Null, "", Matcher1.Group(3)))

    Return Result
End Sub
 
Upvote 0
Top