Given a arbitary string I want to grab an hour (HH:MM) from the string.
Here is my regex:
^ # Start of string
(?: # Try to match...
(?: # Try to match...
([01]?\d|2[0-3]): # HH:
)? # (optionally).
([0-5]?\d): # MM: (required)
)? # (entire group optional, so either HH:MM:, MM: or nothing)
$ # End of string
And my code:
Public Sub RegexTest()
Dim oRegex As Object
Dim time_match As Object
Set oRegex = CreateObject("vbscript.regexp")
With oRegex
.Global = True
.Pattern = "^(?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)$" 'HH:MM
End With
Dim s As String: s = "START TIME: Mar. 3rd 2016 12:00am"
Set time_match = oRegex.Execute(s)
If time_match.Count = 1 Then
Debug.Print time_match.Matches(0)
Else
End If
End Sub
However I am unable to match here and get no output.
Your ^(?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)$ pattern only matches a full string that starts with an optional HH: part, and and obligatory MM part followed with an obligatory :.
I suggest
(?:[01]?\d|2[0-3]):[0-5]\d
Since you are matching a part of the string.
See regex demo
Related
I have a regular expression that uses the matched value from another REGEX in it. But when I test the regular expression it's not capturing the second regex group. Instead it's treating the group as a string. How would I get this regex to output the group?
Private Sub CreateGraphicsFunction(sender As Object, e As EventArgs)
Dim Regex = New Regex("infoEntityIdent=""(ICN.+?)[""].*?[>]")
Dim ICNFiles = Directory.EnumerateFiles(MoveToPath, "*.*", SearchOption.AllDirectories)
For Each tFile In ICNFiles
Dim input = File.ReadAllText(tFile)
Dim match = Regex.Match(input)
If match.Success Then
GraphicList.Add(match.Groups(1).Value)
Dim Regex2 = New Regex("<!ENTITY " & match.Groups(1).Value & " SYSTEM ""(ICN.+?[.]\w.+?)[""]")
Debug.Write(Regex2) ' outputs !ENTITY ICN-GAASIB0-00-051105-A-0YJB5-00005-A-001-01 SYSTEM "(ICN.+?[.]\w.+)["]
Dim sysFileMatch = Regex2.Match(input)
If sysFileMatch.Success Then
ICNList.Add(sysFileMatch.Groups(1).Value)
Debug.Write("found ICN " & sysFileMatch.Groups(1).Value)
End If
End If
Next
End Sub
Examples
the first Regex captures the ICN number. E.g
Using this regex captures the ICN number.
New Regex("infoEntityIdent=""(ICN.+?)[""].*?[>]")
From there I want to use the value captured in the group to go through the file again and find the matching ICN with ext. E.g
So I use the captured group from the first regex in the new regex to get the ICN number with extension.
New Regex("<!ENTITY " & match.Groups(1).Value & " SYSTEM ""(ICN.+?[.]\w.+?)[""]")
When I test this Regex out put it gives me
!ENTITY ICN-GAASIB0-00-051105-A-0YJB5-00005-A-001-01 SYSTEM "(ICN.+?[.]\w.+)["]
It's ignoring the second Regex grouping and instead treating it like part of the string instead of being used as a group. What I want is the ICN number with extension after SYSTEM
Lastest Code sample to try to get it to work
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Files = Directory.EnumerateFiles(MovePath, "*.*", SearchOption.AllDirectories)
For Each tFile In Files
Dim input = File.ReadAllText(tFile)
Dim strREGEX = New Regex("(?=[\S\s]*?infoEntityIdent\s*=\s*""\s*(ICN[\S\s]+?)\s*""[\S\s]*?>)[\S\s]*?<!ENTITY\s+\1\s+SYSTEM\s+""\s*(ICN[\S\s]+?\.\w[\S\s]+?)\s*")
Dim match = strREGEX.Match(tFile)
If match.Success Then
Debug.Write(match.Groups(2).Value)
Else
Debug.Write(match.Groups(2).Value & " was not found")
End If
Next
End Sub
Combine both regex into a single regex.
This avoids the hassle of human intervention error.
This is both your actual regex combined into a single regex.
I've adjusted it so it's a good regex now.
If it doesn't match, I have no way of checking it, you've never
posted a target string.
Raw: (?=[\S\s]*?infoEntityIdent\s*=\s*"\s*(ICN[\S\s]+?)\s*"[\S\s]*?>)[\S\s]*?<!ENTITY\s+\1\s+SYSTEM\s+"\s*(ICN[\S\s]+?\.\w[\S\s]+?)\s*"
Stringed: #"(?=[\S\s]*?infoEntityIdent\s*=\s*""\s*(ICN[\S\s]+?)\s*""[\S\s]*?>)[\S\s]*?<!ENTITY\s+\1\s+SYSTEM\s+""\s*(ICN[\S\s]+?\.\w[\S\s]+?)\s*"""
Formatted and Explained:
(?= # Look ahead to find the ID ICN
[\S\s]*?
infoEntityIdent \s* = \s*
"
\s*
( ICN [\S\s]+? ) # (1), Entity IDent ICN
\s*
"
[\S\s]*? >
)
# Consume now:
[\S\s]*? # Find the ID ICN inside an ENTITY
<!ENTITY \s+
\1 # Back reference to Entity IDent ICN
\s+ SYSTEM \s+
"
\s*
( # (2 start), Some other ICN junk
ICN
[\S\s]+?
\.
\w
[\S\s]+?
) # (2 end)
\s*
"
You are most likely going to want to "escape" your "unknown" result from your first search to be able to use it in your new regular expression.
Something like:
Dim EscapedSearchValue As String = Regex.Escape(match.Groups(1).Value)
Dim Regex2 = New Regex("<!ENTITY " & EscapedSearchValue & " SYSTEM ""(ICN.+?[.]\w.+?)[""]")
See Regex.Escape(String) Method
I have a multi-line string variable that holds a large data string. Some of that data is enclosed between square brackets.
Example data variable:
[text 123]
text [text] 234 [blah] blah
some more [text 123]
I need to extract all the data between the square brackets into a query or table, so it would be something like this:
text 123
test
blah
text 123
Here is my VBA code below:
Dim dataString As String
dataString = "test [field 1] mroe text [field 2] etc"
Dim searchStr As String
Dim regExp As Object
Dim colregmatch As MatchCollection
Dim match As Variant
searchStr = dataString
Set regExp = CreateObject("vbscript.regexp")
With regExp
.pattern = "(?<=\[)(.*?)(?=\])"
.IgnoreCase = True
.Global = True
.Multiline = True
End With
Set colregmatch = regExp.Execute(searchStr)
If colregmatch.Count <> 0 Then
For Each match In colregmatch
MsgBox match.Value
Debug.Print match.Value
Next
End If
Set colregmatch = Nothing
Set regExp = Nothing
UPDATE: I get a 5017 run time error when using this pattern. If I use "[([^]]+)]" as the pattern, it works but the brackets are not removed...
The following regex should work:
/(?<=\[).*?(?=\])/gm
See Regex Demo of the regex in action.
Regex Breakdown:
(?<=\[): Positive lookbehind
\[: matches the character [ literally (case sensitive)
.*?: matches any character (except for line terminators) lazily (as few as possible)
(?=\]): Positive lookahead
\]: matches the character ] literally (case sensitive)
gm: global and multi-line modifiers
I have two strings with the same amount:
Price $22.00
Price Max=$22.00
Can someone please advise how I can modify this regex pattern to make sure that the price with a "Max" in front of it will be ignored?
(?:MAX=|MAX=\s)[$]?[0-9]{0,2}?[,]?[0-9]{1,3}[.][0-9]{0,2}
You may capture the MAX= into an optional capturing group and check if it matched when all matches are found. Only grab the value if the Group 1 did not match:
Dim strPattern As String: strPattern = "(MAX=\s*)?\$\d[\d.,]*"
Dim regEx As Object
Dim ms As Object, m As Object
Set regEx = CreateObject("VBScript.RegExp")
regEx.Global = True
regEx.Pattern = strPattern
Dim t As String
t = "Price $24.00 Price Max=$22.00 "
Set ms = regEx.Execute(t)
For Each m In ms
If Len(m.SubMatches(0)) = 0 Then
Debug.Print m.value
End If
Next
The (MAX=\s*)?\$\d[\d.,]* pattern matches MAX= and 0+ whitespaces into an optional group, it matches 1 or 0 times. \$\d[\d.,]* will match a digit and any 0+ digits, commas and dots. If Len(m.SubMatches(0)) = 0 Then will check if Group 1 is not empty, and if yes, the match is valid.
One way to do it could be to match what you don't want and to capture what you do want in a capturing group using an alternation:
Max=\s*\$[0-9]+\.[0-9]+|(\$[0-9]+\.[0-9]+)
I'm writing a VBA function to evaluate whether a String is a Valid Full Name or not. For example:
Válid Full Name:
David Gilmour
Juan Munoz
Claudio Alberto da Silva
Invalid Full Name:
David Gilm01ur Jr.
Juan Muñoz
Cláudio Alberto da Silva
So the code of my function is this:
Function isVálidoNome(ByVal Texto As String) As Boolean
isVálidoNome = False
'
Dim strPattern As String: strPattern = "(^[a-zA-Z]+(\s?[a-zA-Z])*)*"
'Dim strPattern As String: strPattern = "\d"
Dim regularExpressions As New RegExp
'
regularExpressions.Pattern = strPattern
regularExpressions.Global = True
'
If (regularExpressions.Test(Texto)) Then
isVálidoNome = True
End If
End Function
The pattern I used (^[a-zA-Z]+(\s?[a-zA-Z])*)* works fine in an app I used to test it (RegexPal), but when I run the code in VBA, Strings with digits, accents returns true
Why this problem or Did I make any mistake?
You need to use
^[a-zA-Z]+(?:\s[a-zA-Z]+)*$
See the regex demo
Set regularExpressions.Global = False.
Details:
^ - start of string
[a-zA-Z]+ - 1 or more ASCII letters
(?: - start of a non-capturing group matching zero or more (*) sequences of:
\s - a single whitespace (add + after it to match 1 or more whitespaces)
[a-zA-Z]+
)* - end of the non-capturing group
$ - end of string.
This is something I stumbled across while trying to learn a little about Reg Ex.
Set objRegEx = CreateObject("VBScript.RegExp")
Dim re, targetString, colMatch, objMatch
Set re = New RegExp
With re
.Pattern = "(\d{2}) (\d{2}) (\d{2}) 0500Z"
.Global = True
.IgnoreCase = True
End With
targetString = "02 04 14 0500Z Joe is eating a sandwich"
Set colMatch = re.Execute(targetString)
For each objMatch in colMatch
WScript.echo objMatch
date1 = objRegEx.Replace(objMatch, "(\d{2})(\d{2})(\d{2})")
Wscript.Echo date1
ISSUE: I need to find the date which shows up like this "02 04 14 0500Z" and then assign it to a variable in the form "020414".
When I try to replace the Obj match and reformat the date it doesn't work, instead showing the exact text in brackets.
I referenced:
http://www.mikesdotnetting.com/Article/24/Regular-Expressions-and-VBScript
http://wiki.mcneel.com/developer/scriptsamples/regexpobject
To refer to content captured by capturing group, use $n in the replacement string (where n is a number):
date1 = re.Replace(objMatch, "$1$2$3")
To identify the number of a capturing group, count the number of opening parentheses ( that belongs to a capturing group up to the capturing group you want to refer to:
(\d{2}) (\d{2}) (\d{2}) 0500Z
^ ^ ^
1 2 3
A more complicated example:
((a(?:k)*)(b(c)(?:d)*))
^^ ^ ^
12 3 4
(?:pattern) is a non-capturing group, so it doesn't count.