find a complex string in a substring in VBA - vba

how can I get in VBA a complex string in a substring, e.g. if i = InStr("test-VBA", " this is a test") then msgbox "a part of searching Item exist"
with function "Instr" didn't work because the seraching word is "test-VBA" and ofcourse dosen't
exist as a one word but what I search for if a complete part of the searching item ("test" in the
example as part of "test-VBA") exists should I get a msgbox like described above
Thanks a lot.

Function IsInStr_IgnoreCase(ByVal Str As String, ByVal Value As String) As Boolean
Dim objRegEx as Object
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.pattern = Value
IsInStr_IgnoreCase = objRegEx.test(Str) ' objRegEx.test(Str) returns True if Sustr exists.
End Function
Sub test()
' this returns TRUE if you get a match
MsgBox IsInStr_IgnoreCase_AsBoolean("CHINA-Country", "Move the dev from China to Newseeland")
' this returns all matches of 'Value' in 'Str'
MsgBox IsInStr_IgnoreCase_AsString("CHINA-Country", "Move the dev from China to Newseeland")
' you need to adjust objRegEx.Pattern if you need to get a specific match. See RegEx.
End Sub
Function IsInStr_IgnoreCase_AsBoolean(ByVal Value As String, ByVal Value As String) As Boolean
Dim objRegEx As Object
Dim tStr, tVal, iStr, iVal
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Global = True
objRegEx.Pattern = "(\b\w+)|(\b\d+)"
Set tStr = objRegEx.Execute(Str)
Set tVal = objRegEx.Execute(Value)
objRegEx.IgnoreCase = True
For Each iStr In tStr
For Each iVal In tVal
objRegEx.Pattern = iVal
If objRegEx.test(iStr) Then
IsInStr_IgnoreCase_AsBoolean = True
Exit Function
End If
Next
Next
End Function
Function IsInStr_IgnoreCase_AsString(ByVal Str As String, ByVal Value As String) As String
Dim objRegEx As Object
Dim tStr, tVal, iStr, iVal
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Global = True
objRegEx.Pattern = "(\b\w+)|(\b\d+)"
Set tStr = objRegEx.Execute(Str)
Set tVal = objRegEx.Execute(Value)
objRegEx.IgnoreCase = True
For Each iStr In tStr
For Each iVal In tVal
objRegEx.Pattern = iVal
If objRegEx.test(iStr) Then
IsInStr_IgnoreCase_AsString = IsInStr_IgnoreCase_AsString & iStr & "; "
End If
Next
Next
End Function

Related

finding variables in textboxes

I have an issue when using textboxes that contains variables in word2016.
I would like to preform a search for a variable that may exist within textbox's text, and during certain instances I would like to replace it with a new variable. An example textbox is shown below :
I want to search for the DOCPROPERTY "Checked By". This DOCPROPERTY does not exist in the textbox but the text "Checked By" does , but my code as attached below finds it regardless. Since it is not a DOCPROPERTY, it should not return true.
' ************************************************************
' ********* finding docproperties in text, headers and textboxes
' **************************************************************
Public Function findProperty(doc As Document, findText As String) As Boolean
Dim rngStory As word.Range
Dim oFld As word.Field
Dim objShape As Shape
Dim temp As String
Dim temp2() As String
Dim element As Variant
ActiveWindow.View.ShowFieldCodes = True
If findText = "_DocumentTitle" Then
findProperty = True
Exit Function
End If
findProperty = False
For Each objShape In ActiveDocument.Shapes
If objShape.Type = msoTextBox Then
'do the required action
temp2 = Split(objShape.TextFrame.TextRange.Text, "DOCPROPERTY")
For Each element In temp2
temp = replace(element, "DOCPROPERTY", "")
temp = replace(temp, "\* MERGEFORMAT", "")
temp = replace(temp, """", "")
If InStr(UCase(temp), Trim(UCase(findText))) > 0 Then
findProperty = True
Exit Function
End If
Next
End If
Next objShape
For Each rngStory In doc.StoryRanges
Do
For Each oFld In rngStory.Fields
'If oFld.Type = wdFieldDocProperty Then
'Dig a little deeper and see what the field code contains.
'Formatting of property is a pain....
temp = replace(oFld.Code.Text, "DOCPROPERTY", "")
temp = replace(temp, "\* MERGEFORMAT", "")
temp = replace(temp, """", "")
If Trim(UCase(temp)) = Trim(UCase(findText)) Then
findProperty = True
Exit Function
End If
Next oFld
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next rngStory
ActiveWindow.View.ShowFieldCodes = False
End Function
You're splitting a string into an array using "DOCPROPERTY" as the delimiter, so there is no need to replace "DOCPROPERTY" with vbNullString, ("").
temp2 = Split(objShape.TextFrame.TextRange.Text, "DOCPROPERTY")
For Each element In temp2
temp = replace(element, "DOCPROPERTY", "")
I think that you can test the size of temp2, if it is bigger than 0 then there was a "DOCPROPERTY" found, if it is 0 then there was no "DOCPROPERTY" found.
if UBound(temp2) > 0 then findProperty = True
But probably a better way is to look at Field(n).code which returns the field code text and then you know exactly what you have...
With the suggestion from #SlowLearner is the working code presented below.
Public Function findProperty(doc As Document, findText As String) As Boolean
Dim rngStory As word.Range
Dim oFld As word.Field
Dim objShape As Shape
Dim element As Variant
findProperty = False 'default false
'**************************************************************************************
'**************** ALL DOCUMENTS NEED A TITLE EVEN IF ITS NOT IN USE *******************
'**************************************************************************************
If findText = "_DocumentTitle" Then
findProperty = True
Exit Function
End If
For Each objShape In ActiveDocument.Shapes
If objShape.Type = msoTextBox Then
'do the required action
For Each element In objShape.TextFrame.TextRange.Fields
If InStr(UCase(element.Code.Text), Trim(UCase(findText))) > 0 Then
findProperty = True
Exit Function
End If
Next element
End If
Next objShape
For Each rngStory In doc.StoryRanges
Do
For Each oFld In rngStory.Fields
'Dig a little deeper and see what the field code contains.
If InStr(UCase(oFld.Code.Text), Trim(UCase(findText))) > 0 Then
findProperty = True
Exit Function
End If
Next oFld
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next rngStory
End Function

Loop Through Cells & Return Regex Search in Message Box

Question with a possibly very simple answer, but I'm still potty training with VBA. I'm looping through an excel array and searching a very long string for the regex pattern "\.\w*?_\w*?_Tag_\w*?". There is a similar example of this in this post under the accepted answer "Example 3: Loop Through Range."
Instead of finding and replacing text though, I want to display the matched search pattern from each cell of the array in a single message box. I've been searching for several hours but most of the VBA Regex examples I've found use built in functions (which don't loop through an array), but since this will be used by other folks I need to use a macro.
Here's what I have so far. I'm thinking I need another loop outside of my For Each loop but not sure how to start executing on this.
Sub TagNameList()
Dim strPattern As String: strPattern = "\.\w*?_\w*?_Tag_\w*?"
Dim Regx As New RegExp
Dim StrInput As String
Dim Rng As range
Dim LastRow As Long: LastRow = ActiveSheet.UsedRange.Rows.Count
' Set Rng = ActiveSheet.range(Cells(2, 16), Cells(LastRow, 16))
' Set RegxMatch = Regx.Execute(StrInput)
For Each cell In Rng
StrInput = cell.Value
With Regx
.Global = True
.MultiLine = True
.IgnoreCase = True
.Pattern = strPattern
End With
' If Regx.Test(StrInput) Then
' MsgBox (Regx.Replace(StrInput, strReplace))
' Else
' MsgBox ("Not matched")
' End If
Next
End Sub
I'm not clear if you mean a message box for the whole range or one for each cell, but you need to use the matches collection, e.g.
Sub TagNameList()
Dim strPattern As String: strPattern = "\.\w*?_\w*?_Tag_\w*?"
Dim Regx As New RegExp
Dim StrInput As String
Dim Rng As Range
Dim LastRow As Long: LastRow = ActiveSheet.UsedRange.Rows.Count
Dim oMatches As Object, s As String
Set Rng = ActiveSheet.Range(Cells(2, 16), Cells(LastRow, 16))
Set RegxMatch = Regx.Execute(StrInput)
For Each cell In Rng
StrInput = cell.Value
With Regx
.Global = True
.MultiLine = True
.IgnoreCase = True
.Pattern = strPattern
If .Test(cell) Then
Set oMatches = .Execute(cell)
s = s & "," & oMatches(0).Value
End If
End With
Next
MsgBox Mid(s, 2)
End Sub

Extract text from string starting and ending by specific char

I've got the code below which is extracting a string from brackets and it's ok, but now I've found out that sometimes in my string there can be more brackets with texts behind and I need to extract them too. For instance, a list or table.
e.g
hsus(irt)bla dsd (got)(rifk)
I need then: irt, got, rifk to list, how to do it?
Public Function extract_value(str As String) As String
dim str as string
dim openPos as integer
dim closePos as integer
dim midBit as string
str = "sometinhf(HELLO)sds"
openPos = instr (str, "(")
closePos = instr (str, ")")
midBit = mid (str, openPos+1, closePos - openPos - 1)
End Function
Sub Main()
Dim s$
s = "hsus(irt)bla dsd (got)(rifk)"
Debug.Print extract_value(s)
End Sub
Public Function extract_value$(s$)
Dim returnS$
Dim v
v = Split(s, Chr(40))
For Each Item In v
If InStr(Item, Chr(41)) Then
returnS = returnS & Chr(32) & Split(Item, ")")(0)
End If
Next
extract_value = Trim$(returnS)
End Function
You can use a Regexp to extract the matching strings directly
Sub Main()
Dim strTest as string
strTest = "hsus(irt)bla dsd (got)(rifk)"
MsgBox GrabIt(strTest)
End Sub
Function GrabIt(strIn As String) As String
Dim objRegex As Object
Dim objRegMC As Object
Dim objRegM As Object
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Pattern = "\((.*?)\)"
.Global = True
If .test(strIn) Then
Set objRegMC = .Execute(strIn)
For Each objRegM In objRegMC
GrabIt = GrabIt & Chr(32) & objRegM.submatches(0)
Next
End If
End With
End Function

Replace all text in text file using regular expression

I have a text file with following text
161624.406 : Send:[sometext1]
161624.437 : Send:[sometext2]
161624.468 : Send:[sometext3]
161624.499 : Send:[sometext4]
161624.531 : Send:[sometext5]
I want to keep only the sometext part in that file. Desired output is
sometext1
sometext2
sometext3
sometext4
sometext5
I am using the following code in Excel-VBA
Public Sub testa()
a = "C:\Users\pankaj.jaju\Desktop\test.log"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTxtFile = objFSO.OpenTextFile(a, 1)
strText = objTxtFile.ReadAll
objTxtFile.Close
Set objTxtFile = Nothing
Set objRegEx = CreateObject("VBScript.RegExp")
With objRegEx
.Global = True
.MultiLine = True
.Pattern = "\[([^]]+)\]"
Set objRegMC = .Execute(strText)
b = objRegMC(0).SubMatches(0)
End With
Set objRegEx = Nothing
Debug.Print b
End Sub
The problem is the output is displayed as sometext1 only. How do I ReplaceAll in the text file and save the file with the desired text only.
The regex.Replace method should do the trick.
Separate your pattern into groups like this: "(.*?)(\[)([^]]+)(\])(.*?)"
And now you can replace your input string with the matching group which is group three in this case: objRegEx.Replace(strText, "$3")
Here is a helpful link to different examples of Regex within Excel.
I know you've already got your answer. But for a simple program like this, why even utilize regular expressions? Here's a 4 line script that can do the same thing - yes it has been tested.
Dim a, text: a = "C:\testenv\test.log"
text = split(CreateObject("Scripting.FileSystemObject").OpenTextFile(a, 1).ReadAll, vbcrlf)
for i=0 to ubound(text) : text(i) = replace(split(text(i), "[")(1), "]", "") : next
CreateObject("Scripting.FileSystemObject").OpenTextFile(a, 2).Write(Join(text, vbcrlf))
The regex obviously only grabbing the first match of the string. I'm not proficient enough with regex to come up with a regex only solution that takes into account \n
A simple workaround would be to use objTxtFile.ReadLine instead of ReadAll
Read each string in one by one, apply regex and get output.
Public Sub testa()
a = "C:\Users\pankaj.jaju\Desktop\test.log"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTxtFile = objFSO.OpenTextFile(a, 1)
Do Until (objTxtFile.AtEndOfStream) 'Loop till EOF
strText = objTxtFile.ReadLine 'Single line read instead of ReadAll
Set objRegex = CreateObject("VBScript.RegExp")
With objRegex
.Global = True
.MultiLine = True
.Pattern = "\[([^]]+)\]"
Set objRegMC = .Execute(strText)
b = objRegMC(0).SubMatches(0)
End With
Set objRegex = Nothing
Debug.Print b 'replace this with the code to output the string where you want etc
Loop
objTxtFile.Close
End Sub
OK ... found a way to do it (Thanks MSDN ... sometimes the docs are useful :-)). Sharing the answer
Public Sub testa()
a = "C:\Users\pankaj.jaju\Desktop\test.log"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTxtFile = objFSO.OpenTextFile(a, 1)
strText = objTxtFile.ReadAll
objTxtFile.Close
Set objTxtFile = Nothing
b = ""
Set objRegEx = CreateObject("VBScript.RegExp")
With objRegEx
.Global = True
.MultiLine = True
.Pattern = "\[([^]]+)\]"
Set objMatches = .Execute(strText)
For Each Match In objMatches
For Each SubMatch In Match.SubMatches
b = b & SubMatch & vbCrLf
Next SubMatch
Next Match
End With
Set objRegEx = Nothing
Set objTxtFile = objFSO.OpenTextFile(a, 2)
objTxtFile.Write b
objTxtFile.Close
Set objTxtFile = Nothing
End Sub
EDIT - Based on #PortlandRunner's suggestion
Public Sub testa()
a = "C:\Users\pankaj.jaju\Desktop\test.log"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTxtFile = objFSO.OpenTextFile(a, 1)
strText = objTxtFile.ReadAll
objTxtFile.Close
Set objTxtFile = Nothing
b = ""
Set objRegEx = CreateObject("VBScript.RegExp")
With objRegEx
.Global = True
.MultiLine = True
.Pattern = "(.*?)(\[)([^]]+)(\])(.*?)"
b = objRegEx.Replace(strText, "$3")
End With
Set objRegEx = Nothing
Set objTxtFile = objFSO.OpenTextFile(a, 2)
objTxtFile.Write b
objTxtFile.Close
Set objTxtFile = Nothing
End Sub

Converting String to Double in Excel / Macro

I try create new function in Excel, witch will counting given values (something like SUM function, but only with given prefix).
A
---------
1|AA30
2|AA10
3|BC446
4|AA10
// result will be 50 on SUM_PREFIX(A1:A4;"AA")
Problem is, when the value is in the form e.g AA10,434 or AA4.43. Could me anyone help me with my problem? This is my first stript in VB.
Function SUM_PREFIX(Data As Range, prefix As String) As Double
Dim result As Double
Dim strVal As String
Dim i As Integer
Dim objRegExp As Object
Set objRegExp = CreateObject("vbscript.regexp")
With objRegExp
.IgnoreCase = True
.MultiLine = False
.Pattern = "^[" + prefix + "]+[0-9]+(\,|\.)?[0-9]?$"
.Global = True
End With
For i = 1 To Data.Rows.Count
Debug.Print Data.Cells(i, 1)
If objRegExp.Test(Data.Cells(i, 1)) = True Then
strVal = Replace(Data.Cells(i, 1), prefix, "")
Debug.Print strVal
strVal = Trim(Replace(strVal, ",", "."))
Debug.Print strVal
result = result + CDbl(strVal)
End If
Next i
SUM_PREFIX = result
End Function
Thanks for help.
CDbl is locale-aware, so check if your Replace is correct (for example, in my locale, I have to replace "." by "," in order for it to work).
If you don't want to rely on locale-aware code, use Val instead of CDbl because Val only recognizes "." as a valid decimal separator regardless of locale.
Function SUM_PREFIXO(DADOS As Range, PREFIXO As String) As Double
Dim result, NI As Double
Dim strVal As String
Dim i As Integer
Dim objRegExp As Object
Set objRegExp = CreateObject("vbscript.regexp")
With objRegExp
.IgnoreCase = True
.MultiLine = False
.Pattern = "^[" + PREFIXO + "]+[0-9]+(\,|\.)?[0-9]?$"
.Global = True
End With
NI = DADOS.Rows.Count
For i = 1 To DADOS.Rows.Count
Debug.Print (DADOS.Cells(i, 1))
If objRegExp.Test(RetiraEspaço(DADOS.Cells(i, 1))) = True Then
strVal = Trim(Replace(DADOS.Cells(i, 1), PREFIXO, ""))
Debug.Print strVal
strVal = Trim(Replace(strVal, ".", ","))
Debug.Print strVal
strVal = Trim(Replace(strVal, ",", ","))
Debug.Print strVal
result = result + CDbl(strVal)
End If
Next i
SUM_PREFIXO = result
End Function
'Com o código abaixo pode-se
'remover os espaços extras entre as palavras de um texto:
Function RetiraEspaço(Texto)
Dim Vpalavra, inicio, termino, Wresultado
inicio = 1
Texto = UCase(Texto) & " "
Do Until InStr(inicio, Texto, " ") = 0
termino = InStr(inicio, Texto, " ")
Vpalavra = Mid(Texto, inicio, termino - inicio)
inicio = termino + 1
Wresultado = Wresultado & "" & Vpalavra
Loop
RetiraEspaço = Trim(Wresultado)
End Function