I am trying to use regular expressions in VBA to search in a specific file sheet.
I am trying to filter certain data.
I believe there is an issue with how to set my worksheet to the required value.
Dim RE As Object
Dim LSearchRow As Long
Dim LCopyToRow As Long
Dim ws As Worksheet
Set ws = Worksheets("Values")
On Error GoTo Err_Execute
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = "(T04)"
RE.Ignorecase = True
LSearchRow = 5 'Start search in row 5
LCopyToRow = 3 'Start copying data to row 2 in Sheet2 (row counter variable)
While Len(Cells(LSearchRow, "A").Value) > 0
If RE.test(Cells(LSearchRow, "H").Value) Then
'i believe this is the problem area, If i use active.Rows there isnt an issue
ws.Rows(LSearchRow).Copy Sheets("Filtered T04").Rows(LCopyToRow)
LCopyToRow = LCopyToRow + 1 'Move counter to next row
End If
LSearchRow = LSearchRow + 1
Wend
Range("A3").Select 'Position on cell A3
MsgBox "All matching data has been copied."
Exit Sub
Err_Execute:
MsgBox "An error occurred."
End Sub
You need to properly refer to your set ws. Lines like:
While Len(Cells(LSearchRow, "A").Value) > 0
Will refer to the currently ActiveSheet. So, my guess is that you want to use the below:
Sub Test()
Dim RE As Object
Dim LSearchRow As Long
Dim LCopyToRow As Long
Dim ws As Worksheet
Set ws = Worksheets("Values")
'On Error GoTo Err_Execute
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = "(T04)"
RE.Ignorecase = True
LSearchRow = 5 'Start search in row 5
LCopyToRow = 3 'Start copying data to row 2 in Sheet2 (row counter variable)
While Len(ws.Cells(LSearchRow, "A").Value) > 0
If RE.Test(ws.Cells(LSearchRow, "H").Value) Then
ws.Rows(LSearchRow).Copy Sheets("Filtered T04").Rows(LCopyToRow) 'i believe this is the problem area, If i use active.Rows there isnt an issue
LCopyToRow = LCopyToRow + 1 'Move counter to next row
End If
LSearchRow = LSearchRow + 1
Wend
ws.Range("A3").Select 'Position on cell A3
MsgBox "All matching data has been copied."
Exit Sub
'Err_Execute:
'MsgBox "An error occurred."
End Sub
The above code runs/works, but make sure you haven't made an error in naming your ws variable. If you still hit an error please let us know what line it occurs.
Note: Just one thing I would do in your case is look into AutoFilter as an alternative to RegEx since you don't really use a regular expression but rather need to know if a substring exists in a cell. This would eliminate the need of iteration
Related
I am trying to paste the cell contents based on a condition that if there is no match then copy the first word of the cell and paste it to the next cell to the right but it gives me object not defined error.
CENTRUM ADVANCE TABLET should copy only CENTRUM
Below is my code
Sub splitUpRegexPattern()
Dim re As Object, c As Range
Dim allMatches
Dim cell As Object
Dim count As Integer
count = 0
For Each cell In Selection
count = count + 1
Next cell
' MsgBox count & " item(s) selected"
Set re = CreateObject("VBScript.RegExp")
re.Pattern = "((\d+(?:\.\d+)?)\s*(m?g|mcg|ml|IU|MIU|mgs|µg|gm|microg|microgram)\b)"
re.IgnoreCase = True
re.Global = True
For Each c In ActiveSheet.Range("D2", ActiveSheet.Range("D2").End(xlDown)).Cells ' Select the range and run the code
Set allMatches = re.Execute(c.Value)
If allMatches.count > 0 Then
c.Offset(0, 1).Value = allMatches(0)
Else
Selection.Copy
c.Offset(0, 1).Value.Paste
End If
Next c
End Sub
Work with split function, Example
Set allMatches = re.Execute(c.Value)
If allMatches.count > 0 Then
c.Offset(0, 1).Value = allMatches(0)
Else
c.Offset(0, 1).Value = Split(c.Value, " ")(0)
End If
Split Function (Visual Basic)
Split (text_string, delimiter, limit, compare)
text_string: Would be C.Value.
delimiter: delimiter would be space character (" ").
limit: leave the limit argument blank because we need to separate out all the words from C.Value.
compare: This would be blank, as blank specifies binary comparison method.
A couple changes I believe you need to make:
c.Copy
c.Offset(0, 1).PasteSpecial
There's no paste property of a value. c is a Range so it has Copy and Paste methods.
For your other question:
Dim LArray() As String
LArray = Split(c.Text, " ")
c.Offset(0, 1).Item(1, 1).Value = LArray(0)
Try something like this
Else
Selection.Copy
Selection.Offset(1, 0).Select
ActiveSheet.Paste
End If
Please see the following code:
Sub CountAndHighlightProblematicCells()
Dim RegExpo As New RegExp
Dim strPattern As String: strPattern = "[^\u0020-\u007E]"
Dim specialCharactersFound As Object
Dim strInput As String
Dim counter As Long
RegExpo.Global = True
RegExpo.MultiLine = True
RegExpo.IgnoreCase = False
RegExpo.Pattern = strPattern
counter = 0
For Each cell In Worksheets(1).Range("A1:A100")
strInput = Worksheets(1).Range(cell.Address).Value
If (RegExpo.Test(strInput)) Then
Worksheets(1).Range(cell.Address).Interior.ColorIndex = 20
counter = counter + 1
End If
Set specialCharactersFound = RegExpo.Execute(strInput)
Next
MsgBox ("Number of affected cells: " & counter)
MsgBox ("Number of special characters found: " & specialCharactersFound.Count)
End Sub
For some reason, the test operation works as expected, but the execute operation does not.
If you think that it has something to do with the for loop, I checked and it does not - the execute operation does not work as expected even when The focus in on one cell only.
What am I doing wrong? I'm not very experienced with VBA generally and RegExp
specifically.
Thanks in advance,
Kurkum
I suggest adding these 2 lines to variable declarations:
Dim specialCharactersFound As New Collection
Dim mtch As Object
and then, instead of the code between counter = 0 and Next, use
counter = 0
Set specialCharactersFound = New Collection ' Initialize the collection for special chars
For Each cell In Worksheets(1).Range("A1:A100")
strInput = Worksheets(1).Range(cell.Address).Value
Set mtch = RegExpo.Execute(strInput) ' Find the matches
For Each objMatch In mtch ' Iterate throug the match collection
specialCharactersFound.Add (mtch(0).Value) ' Add the char found to the collection
Next
Worksheets(1).Range(cell.Address).Interior.ColorIndex = 20
counter = counter + 1 ' Increment the affected cell count
Next
I can't seem to figure out the RegExp to extract the bullet points between two group of words in a word document.
For example:
Risk Assessment:
Test 1
Test 2
Test 3
Internal Audit
In this case I want to extract the bullet points between "Risk Assessment" and "Internal Audit", one bullet at a time and assign that bullet to an Excel cell. As shown in the code below I have pretty much everything done, except I cant figure out the correct Regex pattern. Any help would be great. Thanks in advance!
Sub PopulateExcelTable()
Dim fd As Office.FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.AllowMultiSelect = False
.Title = "Please select the file."
.Filters.Clear
.Filters.Add "Word 2007-2013", "*.docx"
If .Show = True Then
txtFileName = .SelectedItems(1)
End If
End With
Dim WordApp As Word.Application
Set WordApp = CreateObject("Word.Application")
Dim WordDoc As Word.Document
Set WordDoc = WordApp.Documents.Open(txtFileName)
Dim str As String: str = WordDoc.Content.Text ' Assign entire document content to string
Dim rex As New RegExp
rex.Pattern = "\b[^Risk Assessment\s].*[^Internal Audit\s]"
Dim i As long : i = 1
rex.Global = True
For Each mtch In rex.Execute(str)
Debug.Print mtch
Range("A" & i).Value = mtch
i = i + 1
Next mtch
WordDoc.Close
WordApp.Quit
End Sub
This is probably a long way around the problem but it works.
Steps I'm taking:
Find bullet list items using keywords before and after list in regexp.
(Group) regexp pattern so that you can extract everything in-between words.
Store listed items group into a string.
Split string by new line character into a new array.
Output each array item to excel.
Loop again since there may be more than one list in document.
Note: I don't see your code for a link to Excel workbook. I'll assume this part is working.
Dim rex As New RegExp
rex.Pattern = "(\bRisk Assessment\s)(.*)(Internal\sAudit\s)"
rex.Global = True
rex.MultiLine = True
rex.IgnoreCase = True
Dim lineArray() As String
Dim myMatches As Object
Set myMatches = rex.Execute(str)
For Each mtch In rex.Execute(str)
'Debug.Print mtch.SubMatches(1)
lineArray = Split(mtch.SubMatches(1), vbLf)
For x = LBound(lineArray) To UBound(lineArray)
'Debug.Print lineArray(x)
Range("A" & i).Value = lineArray(x)
i = i + 1
Next
Next mtch
My test page looks like this:
Results from inner Debug.Print line return this:
Item 1
Item 2
Item 3
I want to be able to copy raw data into column A, hit run on the macro and it should remove any unwanted characters both before and after the data that I want to keep resulting in a cell just containing the data that I want. I also want it to go through all cells that are in the column, bearing in mind some cells may be empty.
The data that I want to keep is in this format: somedata0000 or somedata000
Sometimes the cell will contain 'rubbish' both before and after the data that I want to keep i.e. rubbishsomedata0000 or somedata0000rubbish or rubbishsomedata0000rubbish.
And also, sometimes a single cell will contain:
rubbishsomedata0000rubbish
rubbishsomedata0000rubbish
rubbishsomedata0000rubbish
This will need to be changed to:
NEW CELL: somedata0000
NEW CELL: somedata0000
NEW CELL: somedata0000
The 'somedata' text will not change but the 0000 (which could be any 4 numbers) will sometimes be any 3 numbers.
Also there may be some rows in the column that have no useful data; these should be removed/deleted from the sheet.
Finally, some cells will contain the perfect somedata0000, these should stay the same.
Sub Test()
Dim c As Range
For Each c In Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row)
c = removeData(c.text)
Next
End Sub
Function removeData(ByVal txt As String) As String
Dim result As String
Dim allMatches As Object
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = "(somedata-\d{4}|\d{3})"
RE.Global = True
RE.IgnoreCase = True
Set allMatches = RE.Execute(text)
If allMatches.Count <> 0 Then
result = allMatches.Item(0).submatches.Item(0)
End If
ExtractSDI = result
End Function
I have put my code that I've got so far, all it does is go through each cell, if it matches it just removes the text that I want to keep as well as the stuff that I want removed! Why?
There are several issues in your code
As Gary said, you Function isn't returning a result
Your Regex.Pattern doesn't make sense
Your Sub doesn't attempt to handle multiple matches
Your Function doesn't even attempt to return multiple matches
Sub Test()
Dim rng As Range
Dim result As Variant
Dim i As Long
With ActiveSheet
Set rng = Range(.Cells(2, 1), .Cells(.Rows.Count, 1).End(xlUp))
End With
For i = rng.Rows.Count To 1 Step -1
result = removeData(rng.Cells(i, 1))
If IsArray(result) Then
If UBound(result) = 1 Then
rng.Cells(i, 1) = result(1)
Else
rng.Cells(i, 1).Offset(1, 0).Resize(UBound(result) - 1, 1).Insert xlShiftDown
rng.Cells(i, 1).Resize(UBound(result), 1) = Application.Transpose(result)
End If
Else
rng.Cells(i, 1).ClearContents
End If
Next
End Sub
Function removeData(ByVal txt As String) As Variant
Dim result As Variant
Dim allMatches As Object
Dim RE As Object
Dim i As Long
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = "(somedata\d{3,4})"
RE.Global = True
RE.IgnoreCase = True
Set allMatches = RE.Execute(txt)
If allMatches.Count > 0 Then
ReDim result(1 To allMatches.Count)
For i = 0 To allMatches.Count - 1
result(i + 1) = allMatches.Item(i).Value
Next
End If
removeData = result
End Function
I need to be able to use regular expressions in an excel macro that will search through a specific column, and then copy and paste all the rows that contain matches into a new sheet.
I have found a script that will search through columns and will paste the matches into a new sheet, but I'm not certain how to modify it use regular expressions instead of a single string.
I'm thinking of using this macro to search, but I need to modify the term 'mail box' to be a regular expression term/object, but I'm not sure how to integrate that.
Sub SearchForString()
Dim LSearchRow As Integer
Dim LCopyToRow As Integer
On Error GoTo Err_Execute
'Start search in row 4
LSearchRow = 4
'Start copying data to row 2 in Sheet2 (row counter variable)
LCopyToRow = 2
While Len(Range("A" & CStr(LSearchRow)).Value) > 0
'If value in column E = "Mail Box", copy entire row to Sheet2
If Range("E" & CStr(LSearchRow)).Value = "Mail Box" Then
'Select row in Sheet1 to copy
Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Select
Selection.Copy
'Paste row into Sheet2 in next row
Sheets("Sheet2").Select
Rows(CStr(LCopyToRow) & ":" & CStr(LCopyToRow)).Select
ActiveSheet.Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
'Go back to Sheet1 to continue searching
Sheets("Sheet1").Select
End If
LSearchRow = LSearchRow + 1
Wend
'Position on cell A3
Application.CutCopyMode = False
Range("A3").Select
MsgBox "All matching data has been copied."
Exit Sub
Err_Execute:
MsgBox "An error occurred."
End Sub
Sub SearchForString()
Dim RE As Object
Dim LSearchRow As Long
Dim LCopyToRow As Long
On Error GoTo Err_Execute
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = "(red|blue)"
RE.Ignorecase = True
LSearchRow = 4 'Start search in row 4
LCopyToRow = 2 'Start copying data to row 2 in Sheet2 (row counter variable)
While Len(Cells(LSearchRow, "A").Value) > 0
If RE.Test(Cells(LSearchRow, "E").Value) Then
ActiveSheet.Rows(LSearchRow).Copy Sheets("Sheet2").Rows(LCopyToRow)
LCopyToRow = LCopyToRow + 1 'Move counter to next row
End If
LSearchRow = LSearchRow + 1
Wend
Range("A3").Select 'Position on cell A3
MsgBox "All matching data has been copied."
Exit Sub
Err_Execute:
MsgBox "An error occurred."
End Sub
Without major changes to your existing sub. Replace:
If Range("E" & CStr(LSearchRow)).Value = "Mail Box" Then
with:
v = Range("E" & CStr(LSearchRow)).Value
If InStr(1, v, "red") > 0 Or InStr(1, v, "blue") > 0 Then