#VALUE error in Excel 2010 RegExp - excel

I am trying to implement Regular Expressions in Excel 2010 on a mac, but with any formulas and data all I get is #VALUE errors
Here is my implementation in a module:
Function RegExp1(ReplaceIn, ReplaceWhat As String, _
ReplaceWith As String, Optional IgnoreCase As Boolean = False)
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
re.IgnoreCase = IgnoreCase
re.Pattern = ReplaceWhat
re.Global = True
RegExp1 = re.Replace(ReplaceIn, ReplaceWith)
End Function
And then in the cell I try:
=RegExp1(D2,"(PR2001\.)(\d)","$100$2")
All of this is executing on cells similar to:
PR2001.1
PR2001.2
PR2001.3
etc... I am trying to add zeros in between the last digit and period to format for easier sorting. Any help would be appreciated

Excel X does not support VBScript, so you will not be able to do this. The functon works and the expression is fine, btw.
What I can suggest to you is to write a function using InStrRev (actually this is a good solution even if you could use regexp).
Function AddZeros(ByVal text As String) As String
Dim lastPeriod As Long
lastPeriod = InStrRev(text, ".")
If lastPeriod <> 0 Then
AddZeros = Left$(text, lastPeriod) & ("00" & Mid$(text, lastPeriod + 1))
Else
AddZeros = text
End If
End Function

Related

VBA Append unique regular expressions to string variable

How can I grab matching regular expressions from a string, remove the duplicates, and append them to a string variable that separates each by a comma?
For example, in the string, "this is an example of the desired regular expressions: BPOI-G8J7R9, BPOI-G8J7R9 and BPOI-E5Q8D2" the desired output string would be "BPOI-G8J7R9,BPOI-E5Q8D2"
I have attempted to use a dictionary to remove the duplicates, but my function is spitting out the dreaded #Value error.
Can anyone see where I'm going wrong here? Or is there any suggestion for a better way of going about this task?
Code below:
Public Function extractexpressions(ByVal text As String) As String
Dim regex, expressions, expressions_dict As Object, result As String, found_expressions As Variant, i As Long
Set regex = CreateObject("VBScript.RegExp")
regex.Pattern = "[A-Z][A-Z][A-Z][A-Z][-]\w\w\w\w\w\w"
regex.Global = True
Set expressions_dict = CreateObject("Scripting.Dictionary")
If regex.Test(text) Then
expressions = regex.Execute(text)
End If
For Each item In expressions
If Not expressions_dict.exists(item) Then expressions_dict.Add item, 1
Next
found_expressions = expressions_dict.items
result = ""
For i = 1 To expressions_dict.Count - 1
result = result & found_expressions(i) & ","
Next i
extractexpressions = result
End Function
If you call your function from a Sub you will be able to debug it.
See the comment below about adding the matches as keys to the dictionary - if you add the match object itself, instead of explicitly specifying the match's value property, your dictionary won't de-duplicate your matches (because two or more match objects with the same value are still distinct objects).
Sub Tester()
Debug.Print extractexpressions("ABCD-999999 and DFRG-123456 also ABCD-999999 blah")
End Sub
Public Function extractexpressions(ByVal text As String) As String
Dim regex As Object, expressions As Object, expressions_dict As Object
Dim item
Set regex = CreateObject("VBScript.RegExp")
regex.Pattern = "[A-Z]{4}-\w{6}"
regex.Global = True
If regex.Test(text) Then
Set expressions = regex.Execute(text)
Set expressions_dict = CreateObject("Scripting.Dictionary")
For Each item In expressions
'A dictionary can have object-type keys, so make sure to add the match *value*
' and the not match object itself
If Not expressions_dict.Exists(item.Value) Then expressions_dict.Add item.Value, 1
Next
extractexpressions = Join(expressions_dict.Keys, ",")
End If
End Function
VBA's regex object actually supports the backreference to a previous capture group. Hence we can get all the unique items through the expression itself:
([A-Z]{4}-\w{6})(?!.*\1)
See an online demo
To put this in practice:
Sub Test()
Debug.Print extractexpressions("this is an example of the desired regular expressions: BPOI-G8J7R9, BPOI-G8J7R9 and BPOI-E5Q8D2")
End Sub
Public Function extractexpressions(ByVal text As String) As String
With CreateObject("VBScript.RegExp")
.Pattern = "([A-Z]{4}-\w{6})(?!.*\1)|."
.Global = True
extractexpressions = Replace(Application.Trim(.Replace(text, "$1 ")), " ", ",")
End With
End Function
Prints:

Identify which capturing group was matched in the evaluated string using regex

Hallo I'm new with regular expressions and im getting a hard time figuring out how to get the group that was matched in the evaluated string using regex in VBA.
There are 4 or more different possibilities of words it can appear in the string followed by 1 or more digits:
W-Point =
WR/KE-Point=
WNr-Point=
SST_P-Nr =
One of this words appear just once in the string
Evaluated string:
"3: CALL U(Base,EZSP,Nr1,Pr-nr=20,Offset=1,Path=2,WNr-Point=20,Pr=65,ON)"
Regexpattern used:
(?:(W-Point=)(\d*)|(SST_P-Nr=)(\d*)|(WR/KE-Point=)(\d*)|(WNr-Point=)(\d*))
So far everything works :Example
Problem: Identify which word/digit pair was matched and get its group number. Right now im looping through the results and discarding the submatches that are empty. is there a better or efficient way to do it ?
Thanks in advance.
Try
Sub test()
Dim s As String
s = "3: CALL U(Base,EZSP,Nr1,Pr-nr=20,Offset=1,Path=2,WNr-Point=20,Pr=65,ON)"
Dim Regex As Object, m As Object
Set Regex = CreateObject("vbscript.regexp")
With Regex
.Global = True
.MultiLine = False
.IgnoreCase = True
.pattern = "(W-Point|WR/KE-Point|WNr-Point|SST_P-Nr)( *= *)(\d*)"
End With
If Regex.test(s) Then
Set m = Regex.Execute(s)(0).submatches
Debug.Print m(0), "'" & m(1) & "'", m(2)
End If
End Sub
update : capture = and any spaces

How to find a cell that contains parenthesis around a number - e.g. (1)

The formula I'm using is:
=IF(SUM(COUNTIF(K6,"*"&{"current","(1)"}&"*")),"within 5 minutes",
IF(SUM(COUNTIF(K6,"*"&{"current","(2)"}&"*")),"within 10 minutes",
IF(SUM(COUNTIF(K6,"*"&{"current","(3)"}&"*")),"within 15 minutes",
IF(SUM(COUNTIF(K6,"*"&{"current","(4)"}&"*")),"within 20 minutes",
IF(SUM(COUNTIF(K6,"*"&{"current","(5)"}&"*")),"within 25 minutes",
IF(SUM(COUNTIF(K6,"*"&{"current","(6)"}&"*")),"within 30 minutes"))))))
The output is pulling any cell that contains both current and 1/2/3 etc.
I need it to pull only cells that contain current and (1)/(2)/(3) etc.
Hoping there's an easy way to make sure the formula includes parentheses!
Here's an example screenshot of the expected outcome:
If VBA and UDF is ok then I advice you to use regex.
Open VBA editor (ALT +F11) and add a module.
Paste the following code and save the Excel workbook as macroactivated workbook (xlsm).
Function Regex(Cell)
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = ".*(current and \(\d+\))"
' or if you want to match optional ()
'RE.Pattern = ".*(current and \(?\d+\)?)"
RE.Global = True
RE.IgnoreCase = True
Set Matches = RE.Execute(Cell)
If Matches.Count <> 0 Then
Regex = Matches.Item(0).submatches.Item(0)
End If
End Function
Use it as a formula like:
=Regex(A1)
It will return the part it's looking for current and [number]
The return of the code can of course be whatever you want.
But I don't understand the logic in your question that is why I return what it is looking for
I see now the logic.
This will return the output as you expect.
Function Regex(Cell)
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = ".*current and \((\d+)\)"
' or if you want to match optional ()
'RE.Pattern = ".*current and \(?(\d+)\)?"
RE.Global = True
RE.IgnoreCase = True
Set Matches = RE.Execute(Cell)
If Matches.Count <> 0 Then
Regex = "within " & Matches.Item(0).submatches.Item(0)*5 & " minutes"
Else
Regex = "False"
End If
End Function
It multiplies the captured number with 5 to get the number of minutes.
If nothing is found then it returns False.
VBA and regex generally means the code in the worksheet is easier to maintain and easier to debug.
In order to make it react to the string with current and (number) then use this code:
Function Regex(Cell)
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = ".*current.*?\((\d+)\)"
RE.Global = True
RE.IgnoreCase = True
Set Matches = RE.Execute(Cell)
If Matches.Count <> 0 Then
Regex = "within " & Matches.Item(0).submatches.Item(0)*5 & " minutes"
Else
Regex = "False"
End If
End Function
This code will look for [anything] current [anything] ([number])
If you really don't want to follow #Andreas suggestion (which is another way of saying "why didn't I think of that"), try:
=IFERROR(IF(FIND("current",A3)>0,CONCATENATE("within ", CHOOSE(VALUE(MID(A3,FIND("(",A3)+1,1)),5,10,15,20,25,30), " minutes"),),FALSE)
Caveat: it ignores the closing parenthesis, so this cell contains current and (1 would not return "FALSE"

Split mixed string in excel

I have an intractable problem. There is this huge, long column at work which contains mixed strings with the following format:
ue6584
th45
hur4562243
So it is very irregular, the only regularity is that it starts with letters and ends with numbers. I need to split the strings in each cell so that:
ue6584 —> ue 6584
th45 —> th 45
hur4562243 —> hur 4562243
So the cell splits into two columns, one column containing the letters only, the other the numbers only. So far, I am thinking this is impossible to do in excel.
Can anyone help please?
Thank you in advance,
Dritan
Or you can use a simple trick with built-in functions:
=LEFT(A1,MIN(FIND({0,1,2,3,4,5,6,7,8,9},A1&"0123456789"))-1) - for string part;
=RIGHT(A1,LEN(A1)-MIN(FIND({0,1,2,3,4,5,6,7,8,9},A1&"0123456789"))+1) - for number part;
You will likely need VBA, so I have created a UDF (plus it gave me an excuse to play with RegEx).
First, add the RegEx reference to the VBEditor. See Step 1 from this post for how to do that.
Then add these to a Module in your workbook:
Function return_letters(ByVal target As Range)
Dim regEx As New RegExp
Dim pattern As String: pattern = "[0-9]"
With regEx
.Global = True
.MultiLine = False
.IgnoreCase = False
.pattern = pattern
End With
If regEx.Test(target) Then
return_letters = (regEx.Replace(target, ""))
End If
End Function
Function return_numbers(ByVal target As Range)
Dim regEx As New RegExp
Dim pattern As String: pattern = "[a-zA-Z]"
With regEx
.Global = True
.MultiLine = False
.IgnoreCase = False
.pattern = pattern
End With
If regEx.Test(target) Then
return_numbers = (regEx.Replace(target, ""))
End If
End Function
Finally, just call each function:

Removing particular string from a cell

I have text in a range of cells like
Manufacturer#||#Coaster#|#|Width (side to side)#||#20" W####Height (bottom to top)#||#35" H#|#|Depth (front to back)#||#20.5" D####Seat Depth#||#14.25"**#|#|Material & Finish####**Composition#||#Wood Veneers & Solids#|#|Composition#||#Metal#|#|Style Elements####Style#||#Contemporary#|#|Style#||#Casual
From this cell i need to remove strings between #|#|"needtoremove"#### only without affecting other strings.
I have tried find and replace, finding #|#|*#### and replacing it with #|#|. However its not giving the exact result.
Can anyone help me?
The other solution will remove anything between the first #|#| and ####, event the #||# etc.
In case you only need to remove the text between #|#| and #### only if there is no other ##|| inbetween, I think the simplest way is to use a regex.
You will need to activate the Microsoft VBScript Regular Expressions 5.5 library in Tools->References from the VBA editor.
Change range("D166") to wherever your cell is. The expression as it is right now ("#\|#\|[A-Za-z0-9& ]*####")matches any text that starts with #|#|, ends with #### and has any number of alphanumerical character, & or space. You can add other caracters between the brakets if needed.
Sub remove()
Dim reg As New RegExp
Dim pattern As String
Dim replace As String
Dim strInput As String
strInput = Range("D166").Value
replace = ""
pattern = "#\|#\|[A-Za-z0-9& ]*####"
With reg
.Global = True
.MultiLine = True
.IgnoreCase = False
.pattern = pattern
End With
If reg.test(strInput) Then Range("D166").Value = reg.replace(strInput, replace)
End Sub
Something like this.
If that value is in cell A1
Dim str As String
Dim i As Integer
Dim i2 As Integer
Dim ws As Excel.Worksheet
Set ws = Application.ActiveSheet
str = ws.Range("A1").Value
i = InStr(str, "#|#|")
i2 = InStr(str, "####")
str = Left(str, i) & Right(str, Len(str) - i2)
ws.Range("A1").Value = str

Resources