How to create a regex VBA macro for GIIN format validation - regex

I'm trying to create a macro that will verify data in one column and then let me know if they are correctly formatted in the next column. I am very new to VBA so I apologize if my code is messy.
The format I am trying to verify is ABC123.AB123.AB.123 -- The first two sections can contain letters/numbers, the third section only letters, and the last section only numbers.
Any guidance would be greatly appreciated!
Function ValidGIIN(myGIIN As String) As String
Dim regExp As Object
Set regExp = CreateObject("VBScript.Regexp")
If Len(myGIIN) Then
.Global = True
.IgnoreCase = True
.Pattern = "[a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][.][a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][a-zA-Z0-9_][.][a-zA-z_][a-zA-z_][.][0-9][0-9][0-9]"
End With
If regExp.Test(myGIIN) = True Then
ValidGIIN = "Valid"
Else
ValidGIIN = "Invalid"
End If
End If
Set regExp = Nothing
End Function

Try the following pattern
[a-zA-Z0-9]{6}\.[a-zA-Z0-9]{5}\.[A-Za-z]{2}\.\d{3}
You could call your function in a loop over cells in a column and use offset(0,1) to write result to next column to right.

Related

Changing formulas on the fly with VBA RegEx

i'm trying to change formulas in excel, i need to change the row number of the formulas.
I'm trying do use replace regex to do this. I use an loop to iterate through the rows of the excel and need to change the formula for the row that is iterating at the time. Here is an exemple of the code:
For i = 2 To rows_aux
DoEvents
Formula_string= "=IFS(N19='Z001';'xxxxxx';N19='Z007';'xxxxxx';0=0;'xxxxxxx')"
Formula_string_new = regEx.Replace(Formula_string, "$1" & i)
wb.Cells(i, 33) = ""
wb.Cells(i, 33).Formula = Formula_string_new
.
.
.
Next i
I need to replace rows references but not the ones in quotes or double quotes. Example:
If i = 2 i want the new string to be this:
"=IFS(N2='Z001';'xxxxxx';N2='Z007';'xxxxxx';0=0;'xxxxxxx')"
I'm trying to use this regex:
([a-zA-Z]+)(\d+)
But its changing everything in quotes too. Like this:
If i = 2:
"=IFS(N2='Z2';'xxxxxx';N2='Z2';'xxxxxx';0=0;'xxxxxxx')"
If anyone can help me i will be very grateful!
Thanks in advance.
As others have written, there are probably better ways to write this code. But for a regex that will capture just the Column letter in capturing group #1, try:
\$?\b(XF[A-D]|X[A-E][A-Z]|[A-W][A-Z]{2}|[A-Z]{2}|[A-Z])\$?(?:104857[0-6]|10485[0-6]\d|1048[0-4]\d{2}|104[0-7]\d{3}|10[0-3]\d{4}|[1-9]\d{1,5}|[1-9])d?
Note that is will NOT include the $ absolute addressing token, but could be altered if that were necessary.
Note that you can avoid the loop completely with:
Formula_string = "=IFS(N19=""Z001"",""xxxxxx"",N$19=""Z007"",""xxxxxx"",0=0,""xxxxxxx"")"
Formula_string_new = regEx.Replace(Formula_string, "$1" & firstRow)
With Range(wb.Cells(firstRow, 33), wb.Cells(lastRow, 33))
.Clear
.Formula = Formula_string_new
End With
When we write a formula to a range like this, the references will automatically adjust the way you were doing in your loop.
Depending on unstated factors, you may want to use the FormulaLocal property vice the Formula property.
Edit:
To make this a little more robust, in case there happens to be, within the quote marks, a string that exactly mimics a valid address, you can try checking to be certain that a quote (single or double) neither precedes nor follows the target.
Pattern: ([^"'])\$?\b(XF[A-D]|X[A-E][A-Z]|[A-W][A-Z]{2}|[A-Z]{2}|[A-Z])\$?(?:104857[0-6]|10485[0-6]\d|1048[0-4]\d{2}|104[0-7]\d{3}|10[0-3]\d{4}|[1-9]\d{1,5}|[1-9])d?\b(?!['"])
Replace: "$1$2" & i
However, this is not "bulletproof" as various combinations of included data might match. If it is a problem, let me know and I'll come up with something more robust.
If you can identify some unique features like in the example preceding bracket ( or colon ; and trailing equal = then this might work
Sub test()
Dim s As String, sNew As String, i As Long
Dim Regex As Object
Set Regex = CreateObject("vbscript.regexp")
With Regex
.Global = True
.MultiLine = False
.IgnoreCase = True
.Pattern = "([(;][a-zA-Z]{1,3})(\d+)="
End With
i = 1
s = "=IFS(NANA19='Z001';'xxxxxx';NA19='Z007';'xxxxxx';0=0;'xxxxxxx')"
sNew = Regex.Replace(s, "$1" & i & "=")
Debug.Print s & vbCr & sNew
End Sub

excel vba - use regex to return information between indicators

I have an app which returns data in the form of a table copied into the clipboard.
the table takes the form of:
table name
other info
-------------------------------
|heading 1|heading 2|heading 3|
-------------------------------
|data|date|other Data|
|data|date|other Data|
-------------------------------
time stamp
etc
I'm looking to pull back only the heading and data rows, minus the horizontal rows which are represented by dashes (---) in my data.
I need the pipes (|) as they are used to split the rows for passing back to excel.
I've used the following regex attempts
strPattern = "(?<=\|)[^|]++(?=\|)"
strPattern = "(\|[^|]++(\|)"
strPattern = "(^\s\|[\d\D]+?\|\s$)"
strPattern = "(^\s\|[\d\D]*\|\s$)"
strReplace = "$1"
thinking that the above uses the pipes as bookends and returns any digit or non digit character between the pipes. none of these work and at best it returns the entire string (I know I don't have anything removing the dashes yet)
looking for:
|heading 1|heading 2|heading 3|
|data|date|other Data|
|data|date|other Data|
Thanks in advance for any help
To answer your question, for a regex that will take your text as a block (multi-line variable) and only return the desired lines, try:
^(?:(?:(?:(?=-).)+)|(?:[^|]+))\n?
There may be better ways to accomplish your overall goal, but this accomplishes what you requested.
Option Explicit
Function PipedLines(S As String)
Dim RE As Object
Const sPat As String = "^(?:(?:(?:(?=-).)+)|(?:[^|]+))\n?"
Set RE = CreateObject("vbscript.regexp")
With RE
.Global = True
.MultiLine = True
.Pattern = sPat
PipedLines = .Replace(S, "")
End With
End Function
Hi #tsuimark have you treid copying Clipboard data to directly to excel.?
tried and attched screenshot. and remove unwanted rows in sheet.
Thanks.

Reverse string search in Excel

Trying to get Column F/VENDOR # to populate the vendor number only. The vendor number are highlighted. My strategy is from the right, find the third "_" and substitute it with a "|". Then anything right of the pipe is populated in column D.
However the ones with more than three "_" are not following the logic. What am I doing wrong?
Column D formula =IF(ISERROR(FIND("_",C2)),"",RIGHT(C2,LEN(C2)-FIND("|",SUBSTITUTE(C2,"_","|",LEN(C2)-LEN(SUBSTITUTE(C2,"_","",3))))))
Column F/Vendor# formula =IF(ISERROR(LEFT(D2,FIND("_",D2)-1)),"",LEFT(D2,FIND("_",D2)-1))
The issue is in the column D formula - you have:
...LEN(C2)-LEN(SUBSTITUTE(C2,"_","",3))...
It should be:
...LEN(C2)-LEN(SUBSTITUTE(C2,"_",""))-2...
Giving a full formula for column D of:
=IF(ISERROR(FIND("_",A17)),"",RIGHT(A17,LEN(A17)-FIND("|",SUBSTITUTE(A17,"_","|",LEN(A17)-LEN(SUBSTITUTE(A17,"_",""))-2))))
The reason is because that part of the formula is really being used to calculate an index in another SUBSTITUTE function. You need to use a relative offset (-2 is kind of 3rd from right) if you have a unknown number of _s in the string.
If you can use VBA then you should look at using an UDF with regular expressions as I feel this is slightly less complex than the double-formula method which is not trivial to step through. The UDF could simply be this:
Option Explicit
Function GetVendorNumber(rng As Range) As String
Dim objRegex As Object
Dim objMatches As Object
GetVendorNumber = ""
Set objRegex = CreateObject("VBScript.RegExp")
With objRegex
.Pattern = "\D+_(\d+)_.+"
Set objMatches = .Execute(rng.Text)
If objMatches.Count = 1 Then
GetVendorNumber = objMatches(0).SubMatches(0)
End If
End With
End Function

Excel VBA using RegEx for Conditional Formating

I have an Excel 2010 VBA macro that does some conditional formatting over a select area of a spreadsheet. As an example the following snippet searches for a text pattern then colors the cell:
Selection.FormatConditions.Add Type:=xlTextString, String:="TextToMatch", _
TextOperator:=xlContains Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.ColorIndex = 36
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
What I would like to add is to match against a regular expression TN[0-9]. A simple match of the string TN followed by a digit.
I have created the RegExp obect:
Dim regEx As Object
Set regEx = CreateObject("VBScript.RegExp")
With regEx
.Pattern = "TN[0-9]"
End With
However I have not figured out how to apply this to the Selection.
As always, thank you for your assistance.
I would recommend using a Static type object for your VBScript.RegExp object.
Cut the range passed into the function down to the Worksheet.UsedRange property. This allows a selection of full columns without calculating empty rows/columns.
Option Explicit
Sub createCFR()
With Selection
'cut Selection down to the .UsedRange so that full row or full
'column references do not use undue calculation
With Intersect(.Cells, .Cells.Parent.UsedRange)
.FormatConditions.Delete
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=myCFR(" & .Cells(1).Address(0, 0) & ")")
.SetFirstPriority
With .Interior
.PatternColorIndex = xlAutomatic
.ColorIndex = 36
.TintAndShade = 0
End With
.StopIfTrue = False
End With
End With
End With
End Sub
Function myCFR(rng As Range)
Static rgx As Object
'with rgx as static, it only has to be created once
'this is beneficial when filling a long column with this UDF
If rgx Is Nothing Then
Set rgx = CreateObject("VBScript.RegExp")
End If
'make sure rng is a single cell
Set rng = rng.Cells(1, 1)
With rgx
.Global = True
.MultiLine = True
.Pattern = "TN[0-9]"
myCFR = .Test(rng.Value2)
End With
End Function
Depending on your Selection, you may need to modify the parameters of the Range.Address property used to create the CFR; e.g. $A1 would be .Address(1, 0).
In the following image, B2:B7 contain =myCFR(A2) filled down to proof the UDF.

Microsoft office Access `LIKE` VS `RegEx`

I have been having trouble with the Access key term LIKE and it's use. I want to use the following RegEx (Regular Expression) in query form as a sort of "verfication rule" where the LIKE operator filters my results:
"^[0]{1}[0-9]{8,9}$"
How can this be accomplished?
I know you were not asking about the VBA, but it maybe you will give it a chance
If you open a VBA project, insert new module, then pick Tools -> References and add a reference to Microsoft VBScript Regular Expressions 5.5. Given that pate the code below to the newly inserted module.
Function my_regexp(ByRef sIn As String, ByVal mypattern As String) As String
Dim r As New RegExp
Dim colMatches As MatchCollection
With r
.Pattern = mypattern
.IgnoreCase = True
.Global = False
.MultiLine = False
Set colMatches = .Execute(sIn)
End With
If colMatches.Count > 0 Then
my_regexp = colMatches(0).Value
Else
my_regexp = ""
End If
End Function
Now you may use the function above in your SQL queries. So your question would be now solved by invoking
SELECT my_regexp(some_variable, "^[0]{1}[0-9]{8,9}$") FROM some_table
if will return empty string if nothing is matched.
Hope you liked it.
I don't think Access allows regex matches (except in VBA, but that's not what you're asking). The LIKE operator doesn't even support alternation.
Therefore you need to split it up into two expressions.
... WHERE (Blah LIKE "0#########") OR (Blah LIKE "0########")
(# means "a single digit" in Access).