I have a RegEx that validates a date coming in. What I want it to allow:
MM/dd/YYYY
M/d/YYYY
MM-dd-YYYY
M-d-YYYY
MM.dd.YYYY
M.d.YYYY
MMddYYYY
And a few other variants.
Here's my expression:
^((0[1-9]|1[012])[- /.]?(0[1-9]|[12][0-9]|3[01])[- /.]?(19|20)\d\d)|((((0?[13578])|(1[02]))[- /.]?((0?[1-9])|([12][0-9])|(3[01]))|((0?[469])|(11))[- /.]?((0?[1-9])|([12][0-9])|(30))|(0?[2])[- /.]?((0?[1-9])|([1][0-9])|([2][0-8])))[- /.]?(19\d{2}|20\d{2}))|(((0?[2]))[- /.]?((0?[1-9])|([12][0-9]))[- /.]?((19|20)(04|08|[2468][048]|[13579][26])|2000))$
I'm getting the majority to work, but the dates that I do not want to work is MdYYYY, MMdYYYY, or MddYYYY
I want the RegEx to be the only thing changed because it's being called in multiple spots for the same reason, limiting the amount of code I need to adjust.
I'm calling this RegEx from this Case statement which is in my custom TextBoxPlus.ascx:
Case TextBoxPlusType.DateOnlyMMDDYYYY
WatermarkText = "mmddyyyy"
ValidationExpression = "^((0[1-9]|1[012])[- /.]?(0[1-9]|[12][0-9]|3[01])[- /.]?(19|20)\d\d)|((((0?[13578])|(1[02]))[- /.]?((0?[1-9])|([12][0-9])|(3[01]))|((0?[469])|(11))[- /.]?((0?[1-9])|([12][0-9])|(30))|(0?[2])[- /.]?((0?[1-9])|([1][0-9])|([2][0-8])))[- /.]?(19\d{2}|20\d{2}))|(((0?[2]))[- /.]?((0?[1-9])|([12][0-9]))[- /.]?((19|20)(04|08|[2468][048]|[13579][26])|2000))$"
ErrorMessage = "Please enter a valid date format<br><b>mm/dd/yyyy<br>mmddyyyy</b>"
This is on the actual aspx.vb page calling TextBoxPlus (my custom control):
If (Not (Date.TryParseExact(IssueDate.Text, "MMddyyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None, New Date))) Then
If (Not (Date.TryParseExact(IssueDate.Text, "MM/dd/yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None, New Date))) Then
showIfBadDate.Visible = True
BadDate_AM.Show()
Else
IssueDate_ = Date.ParseExact(IssueDate.Text, "MM/dd/yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo)
End If
Else
IssueDate_ = Date.ParseExact(IssueDate.Text, "MMddyyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo)
End If
If you're using it in a few places, it would be best to use a function to determine the validity of the strings as dates in the acceptable formats:
Option Infer On
Option Strict On
Imports System.Globalization
Module Module1
Function IsValidDate(s As String) As Boolean
Dim validFormats = {"MM/dd/yyyy", "M/d/yyyy", "MM-dd-yyyy", "M-d-yyyy", "MM.dd.yyyy", "M.d.yyyy", "MMddyyyy"}
Dim dt As DateTime
Dim ci As New CultureInfo("en-US")
Return DateTime.TryParseExact(s, validFormats, ci, DateTimeStyles.None, dt)
End Function
Sub Main()
Dim stringsToTry = {"01/31/2016", "1/31/2016", "01-31-2016", "1-9-2016", "01.31.2016", "1.9.2016", "01312016", "112016", "1212016", "1122016"}
For Each s In stringsToTry
Console.WriteLine("{0,-10}: {1}", s, IsValidDate(s))
Next
Console.ReadLine()
End Sub
End Module
Outputs:
01/31/2016: True
1/31/2016 : True
01-31-2016: True
1-9-2016 : True
01.31.2016: True
1.9.2016 : True
01312016 : True
112016 : False
1212016 : False
1122016 : False
With a small change, you could get the function to return a Nullable(Of DateTime) if it is desirable to get the parsed date if it exists.
Related
I need to use (Regular expression) on the string Mod* followed by a specific one character e.g. "A" , like:
Mod A , Mod_A , Module xx A , Modules (A & B) and so on.
But, with the following conditions:
(1)- if the cell contains any of (Modif* or Moder* or Modr*) and Mod* Plus my specific character then the result is True
(2)- if the cell contains any of (Modif* or Moder* or Modr*) and not Mod* Plus my specific character then the result is False
Please this example and the expected result:
Item Description
Expected Result of RegexMatch
new modified of module A 1
TRUE
new modification of mod A
TRUE
new moderate of mod_A
TRUE
to modules (A & B)
TRUE
new modified and moderate A 1
FALSE
new modification of A
FALSE
new moderate of modify
FALSE
to modules (D & E)
FALSE
Public Function RegexMatch(str) As Boolean
Dim tbx2 As String: tbx2 = "A" 'ActiveSheet.TextBox2.Value
Static re As New RegExp
re.Pattern = "\b[M]od(?!erate).*\b[" & tbx2 & "]\b"
re.IgnoreCase = True
RegexMatch = re.Test(str)
End Function
In advance, great thanks for your kindly help.
Not sure if I understand your requirements correctly: You want rows that contain a word that starts with "mod", but words starting with "Modif" or "Moder" or "Modr" doesn't count. Additionally, a module character (eg "A") needs to be present.
I usually get dizzy when I see longer regex terms, so I try to program some lines of code instead. The following function replaces special characters like "(" or "_" with blanks, splits the string into words and check the content word by word. Easy to understand, easy to adapt:
Function CheckModul(s As String, modulChar As String) As Boolean
Dim words() As String
words = Split(replaceSpecialChars(s), " ")
Dim i As Long, hasModul As Boolean, hasModulChar As Boolean
For i = 0 To UBound(words)
Dim word As String
word = UCase(words(i))
If word Like "MOD*" _
And Not word Like "MODIF*" _
And Not word Like "MODER*" _
And Not word Like "MODR*" Then
hasModul = True
End If
If word = modulChar Then
hasModulChar = True
End If
Next
CheckModul = hasModul And hasModulChar
End Function
Function replaceSpecialChars(ByVal s As String) As String
Dim i As Long
replaceSpecialChars = s
For i = 1 To Len(replaceSpecialChars)
If Mid(replaceSpecialChars, i, 1) Like "[!0-9A-Za-z]" Then Mid(replaceSpecialChars, i) = " "
Next
End Function
Tested as UDF with your data:
Do you have an idea of what is wrong in this code please? It should extract all caps and the pattern "1WO" if available.
For example in "User:399595:Account:ETH:balance", i should have "UAETH" and in "User:197755:Account:1WO:balance" i should have "UA1WO"
Thank you
Option Explicit
Function ExtractCap(Txt As String) As String
Application.Volatile
Dim xRegEx As Object
Set xRegEx = CreateObject("VBSCRIPT.REGEXP")
If xRegEx.Pattern = "[^A-Z]" Then
xRegEx.Global = True
xRegEx.MultiLine = False
ExtractCap = xRegEx.Replace(Txt, "")
Set xRegEx = Nothing
Else: xRegEx.Pattern = "1WO"
ExtractCap = xRegEx.Execute(Txt)
End If
End Function
I'm not a "RegEx" expert, so you may want to try an alternative:
Function ExtractCap(Txt As String) As String
Application.Volatile
Dim i As Long
For i = 1 To Len(Txt)
Select Case Asc(Mid(Txt, i, 1))
Case 65 To 90
ExtractCap = ExtractCap & Mid(Txt, i, 1)
End Select
Next
End Function
while, should the pattern of your data strictly be as you showed, you could also consider:
Function ExtractCap(Txt As String) As String
Application.Volatile
ExtractCap = "UA" & Split(Txt, ":")(3)
End Function
Your RegEx works like this:
Function ExtractCap(Txt As String) As String
Application.Volatile
Dim xRegEx As Object
Set xRegEx = CreateObject("VBScript.RegExp")
With xRegEx
.Pattern = "[^A-Z]"
.Global = True
.MultiLine = False
ExtractCap = .Replace(Txt, vbNullString)
End With
If Txt = ExtractCap Then ExtractCap = "1WO"
End Function
Public Sub TestMe()
Debug.Print ExtractCap("User:399595:Account:ETH:balance")
End Sub
In your code, there were 2 errors, which stopped the execution:
xRegEx was set to Nothing and then it was asked to provide a value;
the check If xRegEx.Pattern = "[^A-Z]" does not actually mean a lot to VBA. E.g., you are setting a Pattern and making a condition out of it. If you want to know whether a pattern exists in a RegEx, you should compare the two strings - before and after the execution of the pattern.
Your problem can be easily solved.
Firstly, I assumed that 1WO can appears at most once in your string.
Based on that assumption, logic is as follows:
Define function, which extracts all capital letters from strings.
Now, in the main function, you split your string first using 1WO as delimeter. Now, pass every string (after splitting) to function, get all the caps from those strings and concatenate them again with 1WO in its place.
Option Explicit
Public Function Extract(str As String) As String
Dim s As Variant
For Each s In Split(str, "1WO")
'append extracted caps with 1WO at the end
Extract = Extract & ExtractCaps(s) & "1WO"
Next
'delete lest 1WO from result
Extract = Left(Extract, Len(Extract) - 3)
End Function
Function ExtractCaps(str As Variant) As String
Dim i As Long, char As String
For i = 1 To Len(str)
char = Mid(str, i, 1)
If Asc(char) > 64 And Asc(char) < 91 And char = UCase(char) Then
ExtractCaps = ExtractCaps & char
End If
Next
End Function
If you put this code in inserted Module, you can use it in a worksheet in formula: =Extract(A1).
I tried myself for the first time at an regex expression.
Why doesnt it show the messagebox ("Pls insert a valid mail!") if the text is wrong?
I imported the Regex
Imports System.Text.RegularExpressions
then i wrote my function
Function emailAddressChecker() As Boolean
Dim regex As Regex = Nothing
Dim regExPattern As String = "^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$"
Dim emailAddress = txtbx_neueEmail.Text
If Regex.IsMatch(emailAddress, regExPattern) Then
Return True
Else
Return False
MessageBox.Show("Pls insert a valid mail!")
txtbx_neueEmail.Text = ""
End If
End Function
then i used my function in an event
Private Sub btn_BestaetigeBearbeitung_Click(sender As Object, e As RoutedEventArgs) Handles btn_BestaetigeBearbeitung.Click
If combx_Auswahl.SelectedIndex = 0 Then
emailAddressChecker()
If emailAddressChecker() = True
MessageBox.Show("Hallo!")
Else
MessageBox.Show("")
End If
Nothing is executed after a Return statement, you should change you code order like this:
Else
MessageBox.Show("Pls insert a valid mail!")
txtbx_neueEmail.Text = ""
Return False
End If
I am trying to use regular Expressions to extract the dates from a string using VBA in Excel.
The string is:
Previous Month: 9/1/2015 - 9/30/2015
Or it can be :
Custom: 9/1/2015 - 9/30/2015
Do you have any idea how can I achieve that? I have never used Regular Expressions before.
RegEx is a poor choice for dates. You could look for : and examine the remaining tokens:
Sub Foo()
Dim result() As Variant
result = GetDates("Previous Month: 9/1/2015 - 9/30/2015")
If UBound(result) Then
Debug.Print result(0)
Debug.Print result(1)
End If
End Sub
Function GetDates(str As String) As Variant()
Dim tokens() As String
tokens = Split(Mid$(str, InStr(str & ": ", ":")), " ")
If (UBound(tokens) = 3) Then
If IsDate(tokens(1)) And IsDate(tokens(3)) Then
GetDates = Array(CDate(tokens(1)), CDate(tokens(3)))
Exit Function
End If
End If
ReDim GetDates(0)
End Function
Try this:
([1-9]|1[012])[/]([1-9]|[1-2][0-9]|3[01])[/](19|20)[0-9]{2}
search a commandtext string for dates and then replace them with a new date
dim regex as object
Set regex = CreateObject("VBScript.RegExp")
regex.Pattern = "\d{1,2}[-/]\d{1,2}[-/]\d{2,4}"
regex.Global = True
Set regexMatches = regex.Execute(CommandText)
for i=0 to regexMatches.Count()
date1 = regexMatches(i)
next
I'm trying to extract date/times from strings with the following patterns and convert them to date types in Access.
"08-Apr-2012 21:26:49"
"...Confirmed by SMITH, MD, JOHN (123) on 4/2/2012 11:11:01 AM;"
Can anyone help?
Try this
Dim d As Date
d = CDate("08-Apr-2012 21:26:49")
Debug.Print Format(d, "dd-MMM-yyyy")
Debug.Print Format(d, "h:m:s")
Will give
08-Apr-2012
21:26:49
use this regex to get date-time between " on " (ie, space on space) and the ";" (first semi-colon after that).
(?<=\ on )(.*?)(?=\;)
As already mentioned by Romeo in his answer, you need to use CDate() to convert a string with a valid date value to a Date variable.
You can get the date value out of the string like this:
(given that the strings always look like the one in the example, " on " (with blanks) before the date and ";" after it):
Public Function Test()
Dim Source As String
Dim Tmp As String
Dim DateStart As Integer
Dim DateEnd As Integer
Dim DateValue As Date
Source = "...Confirmed by SMITH, MD, JOHN (123) on 4/2/2012 11:11:01 AM;"
'find the place in the source string where " on " ends
DateStart = InStr(1, Source, " on ") + 4
'find first semicolon after the date)
DateEnd = InStr(DateStart, Source, ";")
'get the part with the date
Tmp = Mid(Source, DateStart, DateEnd - DateStart)
'convert to date
DateValue = CDate(Tmp)
End Function
Add this function to a VBA module:
' ----------------------------------------------------------------------'
' Return a Date object or Null if no date could be extracted '
' ----------------------------------------------------------------------'
Public Function ExtractDate(value As Variant) As Variant
If IsNull(value) Then
ExtractDate = Null
Exit Function
End If
' Using a static, we avoid re-creating the same regex object for every call '
Static regex As Object
' Initialise the Regex object '
If regex Is Nothing Then
Set regex = CreateObject("vbscript.regexp")
With regex
.Global = True
.IgnoreCase = True
.MultiLine = True
.pattern = "(\d+\/\d+/\d+\s+\d+:\d+:\d+\s+\w+|\d+-\w+-\d+\s+\d+:\d+:\d+)"
End With
End If
' Test the value against the pattern '
Dim matches As Object
Set matches = regex.Execute(value)
If matches.count > 0 Then
' Convert the match to a Date if we can '
ExtractDate = CDate(matches(0).value)
Else
' No match found, jsut return Null '
ExtractDate = Null
End If
End Function
And then use it like this, for instance in a query:
SELECT ID, LogData, ExtractDate(LogData) as LogDate
FROM MyLog
Make sure you check that hte dates returned are in the proper format and make sense to you.
CDate() interprets the date string in different ways depending on your locale.
If you're not getting the desired result, you will need to modify the code to separate the individual components of the date and rebuild them using DateSerial() for instance.