This code is supposed to search from two textboxes on a User Form. It goes through each cell in a range, to check for the words from the textboxes and highlights them in red.
I cannot get the array to work.
Sub testing()
Worksheets("Search Results").Activate
Dim sPos As Long, sLen As Long
Dim SRrng As Range
Dim mywords As Variant
Dim i As Integer
Set SRrng = ActiveSheet.Range("A2:G1000")
mywords = Array(UsrFormTxtBox1, UserFormTextBox2)
For Each SRrng In SRrng
With SRrng
If SRrng.Value Like "*" & mywords & "*" Then
If Not SRrng Is Nothing Then
For i = 1 To Len(SRrng.Value)
sPos = InStr(i, SRrng.Value, mywords)
sLen = Len(mywords)
If (sPos <> 0) Then
SRrng.Characters(Start:=sPos, Length:=sLen).Font.Color = RGB(255, 0, 0)
SRrng.Characters(Start:=sPos, Length:=sLen).Font.Bold = True
i = sPos + Len(mywords) - 1
End If
Next i
End If
End If
End With
Next SRrng
End Sub
There were just two small issues - firstly your line:
For Each SRrng In SRrng
...you need to declare a second range variable to browse within the first range. I have called it cell (which is not a reserved word, unlike Cells):
For Each cell In SRrng
Secondly, your array stores two independent values which must be handled separately. I added a variable m and then used it to loop through the array contents. Full code:
Sub testing()
Worksheets("Search Results").Activate
Dim sPos As Long, sLen As Long
Dim SRrng As Range, cell As Range
Dim mywords As Variant
Dim i As Integer
Set SRrng = ActiveSheet.Range("A2:G1000")
mywords = Array(UsrFormTxtBox1, UserFormTextBox2)
Dim m As Byte
For m = 0 To UBound(mywords)
For Each cell In SRrng
With cell
If cell.Value Like "*" & mywords(m) & "*" Then
If Not cell Is Nothing Then
For i = 1 To Len(cell.Value)
sPos = InStr(i, cell.Value, mywords(m))
sLen = Len(mywords(m))
If (sPos <> 0) Then
cell.Characters(Start:=sPos, Length:=sLen).Font.Color = RGB(255, 0, 0)
cell.Characters(Start:=sPos, Length:=sLen).Font.Bold = True
i = sPos + Len(mywords(m)) - 1
End If
Next i
End If
End If
End With
Next cell
Next m
End Sub
By the way, your code is good but if your range became very large then it would be faster to use Find, like this:
Sub testing2()
Worksheets("Search Results").Activate
Dim sPos As Long, sLen As Long
Dim SRrng As Range, cell As Range
Dim mywords As Variant
Dim i As Integer
Set SRrng = ActiveSheet.Range("A2:G1000")
mywords = Array(UsrFormTxtBox1, UserFormTextBox2)
'mywords = Array("banana", "pear")
Dim m As Byte
Dim c As Range
Dim firstAddress As String
For m = 0 To UBound(mywords)
With ActiveSheet.Range("A2:G1000")
Set c = .Find(mywords(m), LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
For i = 1 To Len(c.Value)
sPos = InStr(i, c.Value, mywords(m))
sLen = Len(mywords(m))
If (sPos <> 0) Then
c.Characters(Start:=sPos, Length:=sLen).Font.Color = RGB(255, 0, 0)
c.Characters(Start:=sPos, Length:=sLen).Font.Bold = True
i = sPos + Len(mywords(m)) - 1
End If
Next i
Set c = .FindNext(c)
If firstAddress = c.Address Then Exit Do
Loop While Not c Is Nothing
End If
End With
Next m
End Sub
Related
Function ArrayRemoveDups(MyArray As Variant) As Variant
Dim nFirst As Long, nLast As Long, i As Long
Dim item As String
' Hello I am trying to remove duplicates from an array as well as ignore blanks. But when i insert blanks inbetween the cells there will be an error
Dim arrTemp() As String
Dim Coll As New Collection
'Get First and Last Array Positions
nFirst = LBound(MyArray)
nLast = UBound(MyArray)
ReDim arrTemp(nFirst To nLast)
'Convert Array to String
For i = nFirst To nLast
arrTemp(i) = CStr(MyArray(i))
Next i
'Populate Temporary Collection
On Error Resume Next
For i = nFirst To nLast
Coll.Add arrTemp(i), arrTemp(i)
Next i
Err.Clear
On Error GoTo 0
'Resize Array
nLast = Coll.Count + nFirst - 1
ReDim arrTemp(nFirst To nLast)
'Populate Array
For i = nFirst To nLast
arrTemp(i) = Coll(i - nFirst + 1)
Next i
'Output Array
ArrayRemoveDups = arrTemp
End Function
Sub ArrTest()
Dim WorkingWS As Worksheet
Set WorkingWS = ActiveSheet
Dim LastActiveCellColumn As Long
LastActiveCellColumn = WorkingWS.UsedRange.Columns.Count
MsgBox LastActiveCellColumn
Dim WorkingRng As Range
Dim strNames(10000) As String
Dim outputArray() As String
Dim i As Long
Dim item As Variant
Dim a As Long
Dim B As Long
a = 0
For Each WorkingRng In WorkingWS.Range(Cells(1, 1), Cells(1, LastActiveCellColumn))
strNames(a) = WorkingRng
a = a + 1
Next
outputArray = ArrayRemoveDups(strNames)
'Output values to Immediate Window (CTRL + G)
a = 0
Do While a < LastActiveCellColumn
If Not outputArray(a) = "" Then
MsgBox outputArray(a)
'carry out action here
End If
a = a + 1
Loop
End Sub
I had help with this code below, that works like a dream, it finds words from all 5 search textboxes and highlights them in red and adds a count to one of the columns. However i want to do the same but for box 1 word is in red and box 2 the word it finds it highlights in green and box 3 in orange etc etc. Is it possible to split out from the array which text box goes to which section of code, then could I change the second full set of loops to look for the word n the second textbox and make the word green?
I hope that makes sense?
Worksheets("Questions").Activate
Dim sPos As Long, sLen As Long
Dim SRrng As Range, cell2 As Range
Dim mywords As Variant
Dim i As Integer
Set SRrng = ActiveSheet.Range("B2:E4000")
mywords = Array(UsrFormSearch.TxtSearch1.Value, UsrFormSearch.TxtSearch2.Value,
UsrFormSearch.TxtSearch3.Value, UsrFormSearch.TxtSearch4.Value, UsrFormSearch.TxtSearch5.Value)
Dim m As Byte
Dim c As Range
Dim firstAddress As String
Dim CountArray() As Variant
ReDim CountArray(1 To SRrng.Rows.Count, 1 To 1)
For m = 0 To UBound(mywords)
With ActiveSheet.Range("B2:E4000")
Set c = .Find(mywords(m), LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
For i = 1 To Len(c.Value)
sPos = InStr(i, c.Value, mywords(m))
sLen = Len(mywords(m))
If (sPos <> 0) Then
c.Characters(Start:=sPos, Length:=sLen).Font.Color = RGB(255, 0, 0)
c.Characters(Start:=sPos, Length:=sLen).Font.Bold = True
i = sPos + Len(mywords(m)) - 1
CountArray(c.Row - SRrng.Cells(1, 1).Row + 1, 1) = CountArray(c.Row - SRrng.Cells(1,
1).Row + 1, 1) + 1
End If
Next i
Set c = .FindNext(c)
If firstAddress = c.Address Then Exit Do
Loop While Not c Is Nothing
End If
End With
Next m
SRrng.Cells(1, 1).Offset(0, SRrng.Columns.Count).Resize(UBound(CountArray, 1), 1).Value2 = CountArray
Something like this would work. Just add in a second array of your RGB values which you can reference during each loop cycle.
Sub TestColor()
Worksheets("Questions").Activate
Dim sPos As Long, sLen As Long
Dim SRrng As Range, cell2 As Range
Dim mywords As Variant, myColors As Variant
Dim i As Integer
Set SRrng = ActiveSheet.Range("B2:E4000")
With UsrFormSearch ' Think the .Value is superfluous - add back in if issues arise
mywords = Array(.TxtSearch1, .TxtSearch2, .TxtSearch3, .TxtSearch4, .TxtSearch5)
End With
myColors = Array(RGB(255, 0, 0), RGB(0, 255, 0), RGB(255, 255, 0), RGB(255, 0, 255), RGB(0, 0, 255))
Dim m As Byte
Dim c As Range
Dim firstAddress As String
Dim CountArray() As Variant
ReDim CountArray(1 To SRrng.Rows.Count, 1 To 1)
For m = 0 To UBound(mywords)
With ActiveSheet.Range("B2:E4000")
Set c = .Find(mywords(m), LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
For i = 1 To Len(c.Value)
sPos = InStr(i, c.Value, mywords(m))
sLen = Len(mywords(m))
If (sPos <> 0) Then
c.Characters(Start:=sPos, Length:=sLen).Font.Color = myColors(m)
c.Characters(Start:=sPos, Length:=sLen).Font.Bold = True
i = sPos + Len(mywords(m)) - 1
CountArray(c.Row - SRrng.Cells(1, 1).Row + 1, 1) = CountArray(c.Row - SRrng.Cells(1, 1).Row + 1, 1) + 1
End If
Next i
Set c = .FindNext(c)
If firstAddress = c.Address Then Exit Do
Loop While Not c Is Nothing
End If
End With
Next m
SRrng.Cells(1, 1).Offset(0, SRrng.Columns.Count).Resize(UBound(CountArray, 1), 1).Value2 = CountArray
End Sub
I have an array with fixed values. How can I find cells in Column B that contain all the 'String' values present in array?
Here is my code
With Worksheets("Data")
Dim kwrSets As Variant
.Activate
kwrSets = .Range("B2:B" & Application.WorksheetFunction.Max(2, .Range("A100000").End(xlUp).Row)).Value
For k = LBound(kwrSets) To UBound(kwrSets)
For i = LBound(arr) To UBound(arr)
Delete entire row if all values of arr not found in kwrSets
Next i
Next k
End With
Following is the updated code based on the answer below but it is giving error "Subscript out of range" in inStr line.
Sub Extractor()
Dim ws As Worksheet, wsd As Worksheet
Dim cell As Variant
Dim tmp As Variant
Dim blnFound As Boolean
Dim j As Long, i As Long
Dim kwrSets() As Variant
Dim arr() As String
Set ws = Worksheets("Sheet1")
With ws
.Activate
For Each cell In .Range("A1:A" & .Cells(.Rows.Count, "B").End(xlUp).Row)
If (cell.Offset(0, 2) = 1) Then
tmp = tmp & cell & "|"
End If
Next cell
If Len(tmp) > 0 Then tmp = Left(tmp, Len(tmp) - 1)
arr = Split(tmp, "|")
End With
Set wsd = Worksheets("Data")
With wsd
.Activate
kwrSets = .Range("B2:B" & Application.WorksheetFunction.Max(2, .Range("A100000").End(xlUp).Row)).Value
For k = LBound(kwrSets) To UBound(kwrSets)
blnFound = True
For i = LBound(arr) To UBound(arr)
If InStr(kwrSets(j, 1), arr(i)) = 0 Then
blnFound = False
Exit For
End If
Next i
Next k
End With
End Sub
Below is some VBA code that gets all of the data in column B into an array, then loops this array checking for the existence of each of the elements in the search array. If any of the search elements are not found, then it exits that loop. If all elements are found then it highlights the cell.
Sub sFindArray()
Dim ws As Worksheet
Dim aSearch() As Variant
Dim aData() As Variant
Dim lngLoop1 As Long
Dim lngLoop2 As Long
Dim lngFirstRow As Long
Dim lngLastRow As Long
Dim lngLBound As Long
Dim lngUBound As Long
Dim blnFound As Boolean
aSearch = Array("a", "b", "c")
lngLBound = LBound(aSearch)
lngUBound = UBound(aSearch)
Set ws = Worksheets("Sheet1")
lngLastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
aData() = ws.Range("B1:B" & lngLastRow)
lngFirstRow = LBound(aData, 1)
lngLastRow = UBound(aData, 1)
For lngLoop1 = lngFirstRow To lngLastRow
blnFound = True
For lngLoop2 = lngLBound To lngUBound
If InStr(aData(lngLoop1, 1), aSearch(lngLoop2)) = 0 Then
blnFound = False
Exit For
End If
Next lngLoop2
If blnFound = True Then
ws.Cells(lngLoop1, 2).Interior.Color = vbRed
End If
Next lngLoop1
End Sub
Regards,
I have a problem with a selfmade vba-code. The makro should solve the following problem: I use a "cockpitfile" It should load the elemts of two worksheets from two different Excel files into two Arrays. The Elements of these Arrays should be subtracted from each other. I want to get the difference from these two elements. As an example: ArrayElm1(1,1) - ArrayElm2(1,1) = ArrayElm3(1,1), ArrayElm1(1,2) - ArrayElm2(1,2) = ArrayElm3(1,2) etc.
On the first sight the code seems to work but when I check the results with my calculater the difference of the elements is wrong. Maybe there is a problem with the UBound because in my Ubound is only Array A?
Hope you can help me!
Sub Differenz1()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'Variabledefinition
Dim i As Long 'Index
Dim j As Long 'Index
Dim k As Long 'Index
Dim ArrayA As Variant 'Array
Dim ArrayB As Variant 'Array
Dim ArrayC(71, 25) As Variant 'Array
Dim myFile1 As String 'Workbookname
Dim myFile2 As String 'Workbookname
Dim wb1 As String 'Workbookname
Dim wb2 As String 'Workbookname
Dim WS_Count1 As Integer 'Count Worksheets
Dim WS_Count2 As Integer 'Count Worksheets
Dim arrays1 As String 'Dimension
Dim arrays2 As String 'Dimension
'Change the actual path
ChDrive "O:\"
ChDir "O:..."
myFile1 = Application.GetOpenFilename
Workbooks.Open Filename:=myFile1, ReadOnly:=True, IgnoreReadOnlyRecommended:=True
wb1 = ActiveWorkbook.Name
WS_Count1 = ActiveWorkbook.Worksheets.Count
myFile2 = Application.GetOpenFilename
Workbooks.Open Filename:=myFile2, ReadOnly:=True, IgnoreReadOnlyRecommended:=True
wb2 = ActiveWorkbook.Name
WS_Count2 = ActiveWorkbook.Worksheets.Count
For k = 1 To WS_Count1
ArrayA = Workbooks(wb1).Worksheets(k).Range("F5:Y75").Value
ArrayB = Workbooks(wb2).Worksheets(k).Range("F5:Y75").Value
For i = LBound(ArrayA, 1) To UBound(ArrayA, 1)
For j = LBound(ArrayA, 2) To UBound(ArrayA, 2)
If Not IsError(ArrayA(i, j)) And Not IsError(ArrayB(i, j)) Then ArrayC(i, j) = ArrayA(i, j) - ArrayB(i, j)
Next j
Next i
ThisWorkbook.Worksheets(k + 1).Range("F5:Y75").Value = ArrayC
Next k
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
You almost had it right, but the issues was that you didn't reset ArrayC
This code creates new sheets in ThisWorkbook for subtractions, and based on your previous question it checks for errors, and performs the subtractions only if both values are numbers
Option Explicit
Public Sub Differenz2()
Const USED_RNG = "F5:Y75" 'Main range
Dim i As Long, j As Long, k As Long, file1 As String, file2 As String, ws1Count As Long
Dim wb1 As Workbook, wb2 As Workbook, arr1 As Variant, arr2 As Variant, arr3 As Variant
'ChDrive "O:\": ChDir "O:..."
file1 = Application.GetOpenFilename: If file1 = "False" Then Exit Sub
file2 = Application.GetOpenFilename: If file2 = "False" Then Exit Sub
Application.ScreenUpdating = False
Set wb1 = Workbooks.Open(Filename:=file1, ReadOnly:=True)
Set wb2 = Workbooks.Open(Filename:=file2, ReadOnly:=True)
ws1Count = wb1.Worksheets.Count
If ws1Count = wb2.Worksheets.Count Then
MakeNewWS ws1Count 'Remove this line if ThisWorkbook is properly setup
For k = 1 To ws1Count
arr1 = wb1.Worksheets(k).Range(USED_RNG).Value
arr2 = wb2.Worksheets(k).Range(USED_RNG).Value
ReDim arr3(1 To 71, 1 To 20) 'reset array, based on USED_RNG ("F5:Y75")
For i = LBound(arr1, 1) To UBound(arr1, 1)
For j = LBound(arr1, 2) To UBound(arr1, 2)
If Not IsError(arr1(i, j)) And Not IsError(arr2(i, j)) Then
If IsNumeric(arr1(i, j)) And IsNumeric(arr2(i, j)) Then
arr3(i, j) = arr1(i, j) - arr2(i, j)
End If
End If
Next
Next
ThisWorkbook.Worksheets(k + 1).Range(USED_RNG) = arr3
Next
End If
wb1.Close False: wb2.Close False: ThisWorkbook.Worksheets(2).Activate
Application.ScreenUpdating = True
End Sub
Private Sub MakeNewWS(ByVal wsCount As Long)
Dim i As Long, ws As Worksheet
With ThisWorkbook.Worksheets
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If Left(ws.Name, 12) = "Subtraction " Then
If .Count = 1 Then .Add
ws.Delete
End If
Next
Application.DisplayAlerts = True
For i = 2 To wsCount + 1
.Add After:=ThisWorkbook.Worksheets(.Count)
ThisWorkbook.Worksheets(.Count).Name = "Subtraction " & i - 1
Next
End With
End Sub
You can ignore the MakeNewWS() sub if ThisWorkbook contains the proper number of sheets
Also, using arrays does improve performance (significantly)
I got help with this code but when it runs it does not execute what it needs to do. I'm trying to extract words that are underlined and italicized from row C of the first sheet and move them to the secondsheet. The expected outcome is in the second image. Would array splitting be of use in this situation? Hopefully the sample data make it more clear.
Sub proj()
For Each cl In Range("C1:C5")
Call CopyItalicUnderlined(cl, Worksheets("Sheet2").Range("A1"))
Next
End Sub
Sub CopyItalicUnderlined(rngToCopy, rngToPaste)
rngToCopy.Copy rngToPaste
Dim i
For i = Len(rngToCopy.Value2) To 1 Step -1
With rngToPaste.Characters(i, 1)
If Not .Font.Italic And Not .Font.Underline Then
.Text = vbNullString
End If
End With
Next
End Sub
Split() could help, but only after you already found out and parsed italic words since Characters() method can be called on Range object only
you could then try the following code:
Option Explicit
Sub proj()
Dim dataRng As range, cl As range
Dim arr As Variant
Set dataRng = Worksheets("ItalicSourceSheet").range("C1:C5") '<--| change "ItalicSourceSheet" with your actual source sheet name
With Worksheets("ItalicOutputSheet") '<--|change "ItalicOutputSheet" with your actual output sheet name
For Each cl In dataRng
arr = GetItalics(cl) '<--| get array with italic words
If IsArray(arr) Then .Cells(.Rows.Count, 1).End(xlUp).Offset(1).Resize(UBound(arr) + 1) = Application.Transpose(arr) '<--| if array is filled then write it down to output sheet first blank cell in column "A"
Next
End With
End Sub
Function GetItalics(rng As range) As Variant
Dim strng As String
Dim iEnd As Long, iIni As Long, strngLen As Long
strngLen = Len(rng.Value2)
iIni = 1
Do While iEnd <= strngLen
Do While rng.Characters(iEnd, 1).Font.Italic And rng.Characters(iEnd, 1).Font.Underline
If iEnd = strngLen Then Exit Do
iEnd = iEnd + 1
Loop
If iEnd > iIni Then strng = strng & Mid(rng.Value2, iIni, iEnd - iIni) & "|"
iEnd = iEnd + 1
iIni = iEnd
Loop
If strng <> "" Then GetItalics = Split(Left(strng, Len(strng) - 1), "|")
End Function
It's not the prettiest solution, but you can take each cell, put their contents in an array. Then, make some room, and "unload them" and move along.
I tested with some simple data, but if you have errors, can you show more examples of text/data?
Sub proj()
Dim cl As Range
Dim x As Long
x = 0
For Each cl In Sheets("Sheet1").Range("C1:C5")
Call CopyItalicUnderlined(cl, Worksheets("Sheet2").Range("A1").Offset(x, 0))
x = x + 1
Next
Call breakOutWords
End Sub
Sub CopyItalicUnderlined(rngToCopy As Range, rngToPaste As Range)
Dim foundWords() As Variant
rngToCopy.Copy rngToPaste
Dim i
For i = Len(rngToCopy.Value2) To 1 Step -1
With rngToPaste.Characters(i, 1)
Debug.Print .Text
If Not .Font.Italic And Not .Font.Underline Then
If .Text <> " " Then
.Text = vbNullString
Else
.Text = " "
End If
End If
End With
Next
rngToPaste.Value = Trim(rngToPaste.Value)
rngToPaste.Value = WorksheetFunction.Substitute(rngToPaste, " ", " ")
End Sub
Sub breakOutWords()
Dim lastRow As Long, i As Long, k As Long, spaceCounter As Long
Dim myWords As Variant
Dim groupRange As Range
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = lastRow To 1 Step -1
' Determine how many spaces - this means we have X+1 words
spaceCounter = Len(Cells(i, 1)) - Len(WorksheetFunction.Substitute(Cells(i, 1), " ", "")) + 1
If spaceCounter > 1 Then
Set groupRange = Range(Cells(i, 1), Cells(WorksheetFunction.Max(2, i + spaceCounter - 1), 1))
groupRange.Select
myWords = Split(Cells(i, 1), " ")
groupRange.Clear
For k = LBound(myWords) To UBound(myWords)
groupRange.Cells(1 + k, 1).Value = myWords(k)
Next k
Else
' how many new rows will we need for the next cell?
Dim newRows As Long
newRows = Len(Cells(i - 1, 1)) - Len(WorksheetFunction.Substitute(Cells(i - 1, 1), " ", ""))
Range(Cells(i, 1), Cells(i + newRows - 1, 1)).EntireRow.Insert
End If
Next i
End Sub
I think this should work - I modified your code to match your example.
Change the top constants to mark where you want to start appending
into Sheet 2
Change names of Worksheets to match your real life sheets
Change range of cells to check in Set rge = ws1.Range("C8:C100")
Example Code:
Option Explicit
Public Sub ExtractUnderlinedItalicizedWords()
' Where to start appending new words '
Const INSERT_COL As Integer = 1
Const START_AT_ROW As Integer = 1
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim rge As Range
Dim cel As Range
Dim c As Object
Dim countChars As Integer
Dim i As Integer
Dim intRow As Integer
Dim strWord As String
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")
intRow = START_AT_ROW
' Define the range of cells to check
Set rge = ws1.Range("C8:C100")
For Each cel In rge.Cells
countChars = cel.Characters.count
' Only do this until we find a blank cell
If countChars = 0 Then Exit For
strWord = ""
For i = 1 To countChars
Set c = cel.Characters(i, 1)
With c.Font
If (.Underline <> xlUnderlineStyleNone) And (.Italic) Then
strWord = strWord & c.Text
Else
If Len(strWord) > 0 Then
ws2.Cells(intRow, INSERT_COL).Value = strWord
intRow = intRow + 1
strWord = ""
End If
End If
End With
Next i
' Get Last Word in cell
If Len(strWord) > 0 Then
ws2.Cells(intRow, INSERT_COL).Value = strWord
intRow = intRow + 1
strWord = ""
End If
Next ' Next cell in column range
End Sub