Excel, search multiple columns for cells that contain partial similar data - excel

Wonder if someone could give me a pointer, or maybe it's already been ask then just a reference, but how can I highlight cells in an excel spreadsheet that contains multiple columns where any portion of a text matches?
Example say cell A2 has the text 'Ionized Sea Salt' and cell D5 has 'Salt'. I would like to highlight those cells because of the matching word 'Salt'.
I don't want to have to add the word I'm searching for in the formula because all the cells and columns will contain hundreds of different strings and I'm looking for matching word(s) per cell.
Thanks

Allthough you should have attempted to at least start coding something, this one is quite fun to work on so hereby my attempt :)
Sub Hightlight()
Dim MyArray() As String
Dim X As Long
Dim C As Range
ActiveSheet.UsedRange.Cells.Interior.Pattern = xlNone 'Clear the hightlighted cells
MyArray() = Split(ActiveCell.Value, " ") 'Get the activecell and split it in array
For X = LBound(MyArray) To UBound(MyArray) 'Loop through your array using .findnext
With ActiveSheet.UsedRange
Set C = .Find(MyArray(X), lookat:=xlPart)
If Not C Is Nothing Then
firstaddress = C.Address
Do
C.Interior.ColorIndex = 37 'color found matched cells
Set C = .FindNext(C)
If C Is Nothing Then
GoTo DoneFinding
End If
Loop While C.Address <> firstaddress
End If
DoneFinding:
End With
Next X
End Sub
The biggest plus of this approach is it wont have to go through thousands of cells, so therefor should be relative fast.
I am sure some true expert can cleanup this code even better :)
Input:
Output:
So.... add a button to your sheet, assign the macro, select a cell, hit the button...

Untested but should work:
Private Sub reset_highlighting()
ActiveSheet.Cells.Interior.Color = xlNone
End Sub
Private Sub highlight_d5()
' Call reset_highlighting < remove comment if you dont want to store prev results
Dim lr as Long
lr = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
Dim search_range as Range: Set search_range = Range(Cells(1,1), Cells(lr, 1))
Dim search_value = Range("D5").Value2
For each cell in search_range
If (InStr(Trim(LCase(cell.Value2)), Trim(LCase(search_value))) != 0) Then
cell.Interior.Color = vbYellow
End If
Next cell
End Sub
Note, you should replace ActiveSheet with Sheets("YourSheetName")
and also might want to adjust your range to fir the criteria
accordingly
PS: Post your efforts of you trying to solve the question in the future. Questions where no attempt was made generally tend to get downvoted here, I only made an exception given you're new here (and I have a good mood today)

Related

finding cell value and delete it in excel vba

I want to return the value of the cell it's found in VBA and clear all of it's content with another 3 rows below it as well, but I'm currently stuck. I can find where the cell is coming from, but it's deleting the whole range instead of the specific range (I'm aware the range("A7:H20") was wrong). How do I select the correct range?
Sub Find_and_remove()
For Each cell In Range("A7:H20")
If cell.Value = Range("Q5") Then
'return the range of that cell and deleted it with 3 row below it'
Range("A7:H20").Clear
End If
Next cell
End Sub
Sub Find_and_remove()
Dim rng As Range
For Each rng In Range("A7:H20")
If rng.Value = Range("Q5") Then Range(rng, rng.Offset(3, 0)).Clear
Next cell
End Sub
Another solution:
I am using a sub to which you pass the parameters:
value to be found
range where to look in and clear contents
number of rows below the found value to be cleared.
Furthermore I am looking from the bottom to the top of the range - otherwise cells could be cleared that contain the string to be found - and then below values won't get cleared:
Option Explicit
'>>> example of how to call the findAndRemove-Sub <<<
Public Sub test_FindAndRemove()
With ActiveSheet ' adjust this to your needs
findAndRemove .Range("Q5"), .Range("A7:H20"), 3
End With
End Sub
'>>>> this is the sub that is doing the work <<<<<
Public Sub findAndRemove(strFind As String, _
rgLookup As Range, _
cntDeleteRowsBelow As Long)
Dim i As Long, c As Range
'start from the bottom and go up
'otherwise you could delete further strFind-cells unintentionally
For i = rgLookup.Rows.Count To 1 Step -1
For Each c In rgLookup.Rows(i).Cells
If c.Value = strFind Then
'ATTENTION:
'at this point there is no check if below row contains the strFind-value!
c.Resize(cntDeleteRowsBelow + 1).Clear
End If
Next
Next
End Sub
You could just use cell.Clear, or if you want the cell cleared and the next 3 below it use something like this
For i = 0 To 3
cell.Offset(i, 0).Clear
Next
I think you mean "return the address of that cell", no? Debug.Print(cell.Address) will get you this info. But you don't actually need it here. Instead of Range("A7:H20").Clear write cell.Resize(1 + i, 1).Clear with i = number of rows you want to clear along with cell itself (no need for a loop).

Find row indices of empty cells in a given range

Is it possible to write a vba macro that determines if there are any empty cells in a given range and returns the row number of that cell?
I'm new to vba and all that I managed to write after searching the internet was something that takes a range and colors every emty cell in it red:
Sub EmptyRed()
If TypeName(Selection) <> "Range" Then Exit Sub
For Each cell In Selection
If IsEmpty(cell.Value) Then cell.Interior.Color = RGB(255, 0, 0)
Next cell
End Sub
The macro does basically what I want, but instead of coloring the empty cell red I would like to know the row index of the empty cell.
A little background info: I have a very large file (about 80 000 rows) that contains many merged cells. I want to import it into R with readxl. Readxl splits merged cells, puts the value in the first split cell and NA into all others. But a completely empty cell would also be assigned NA, so I thought the best thing would be to find out which cells are empty with Excel, so that I know which NA indicate a merged cell or an empty cell. Any suggestions on how to solve this problem are very welcome, thanks!
Edit: To clarify: Ideally, I want to unmerge all cells in my document and fill each split cell with the content of the previously merged cell. But I found macros on the web that are supposed to do exactly that, but they didn't work on my file, so I thought I could just determine blank cells and then work on them in R. I usually don't work with Excel so I know very little about it, so sorry if my thought process is far too complicated.
To do exactly what you state in your title:
If IsEmpty(cell.Value) Then Debug.Print cell.Row
But there are also Excel methods to determine merged cells and act on them. So And I'm not sure exactly what you want to do with the information.
EDIT
Adding on what you say you want to do with the results, perhaps this VBA code might help:
Option Explicit
Sub EmptyRed()
Dim myMergedRange As Range, myCell As Range, myMergedCell As Range
Dim rngProcess As Range
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
Set rngProcess = Range("A1:B10")
For Each myCell In rngProcess
If myCell.MergeCells = True Then
Set myMergedRange = myCell.MergeArea
With myMergedRange
.MergeCells = False
.Value = myCell(1, 1)
End With
End If
Next myCell
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With
End sub
Note that I explicitly declare all variables, and I hard coded the range to check. There are various ways of declaring the range to be checked; using 'Selection' is usually rarely preferred.
Before anything else: From the opposite end of the spectrum, you can use Range.MergeCells or Range.MergeArea to determine if a Cell is part of a Merged Area. But, I digress...
You can use Cell.Row to get the row number. How you return or display that is up to you - could be a Message Box, a delimited string, or an array, or even a multi-area range.
A Sub cannot return anything once called, so you may want a Function instead, e.g. Public Function EmptyRed() As String
(Also, I would recommend you get in the habit of explicitly declaring all of your variables, and perhaps using Option Explicit too, before you run into a typo-based error. Just add Dim cell As Range at the top of the sub for now)
Sub FF()
Dim r, wksOutput As Worksheet
Dim cell As Range, rng As Range, rngArea As Range
With Selection
.UnMerge
'// Get only blank cells
Set rng = .SpecialCells(xlCellTypeBlanks)
'// Make blank cells red
rng.Interior.Color = vbRed
End With
'// Create output worksheet
Set wksOutput = Sheets.Add()
With wksOutput
For Each rngArea In rng.Areas
For Each cell In rngArea
r = r + 1
'// Write down the row of blank cell
.Cells(r, 1) = cell.Row
Next
Next
'// Remove duplicates
.Range("A:A").RemoveDuplicates Array(1), xlNo
End With
End Sub
There are a couple ways:
Sub EmptyRed()
Dim rgn,targetrgn as range
Dim ads as string ‘ return rgn address
Set targetrgn= ‘ your selection
For Each rgn In Targetrgn
If IsEmpty(rgn.Value) Then
‘1. Use address function, and from there you can stripe out the column and row
Ads=application.worksheetfunction.addres(cell,1)’ the second input control the address format, w/o $
‘2. Range.row & range.column
Ads=“row:” & rgn.row & “, col: “ & rgn.column
End if
Next rgn
End Sub
Ps: I edited the code on my phone and will debug further when I have a computer. And I am just more used to use “range” rather than “cell”.
To clarify: Ideally, I want to unmerge all cells in my document and fill each split cell with the content of the previously merged cell.
Cycle through all cells in the worksheet's UsedRange
If merged, unmerge and fill the unmerged area with the value from the formerly merged area.
If not merged but blank, collect for address output.
Sub fillMerged()
Dim r As Range, br As Range, mr As Range
For Each r In ActiveSheet.UsedRange
If r.Address <> r.MergeArea.Address Then
'merged cells - unmerge and set value to all
Set mr = r.MergeArea
r.UnMerge
mr.Value = mr.Cells(1).Value
ElseIf IsEmpty(r) Then
'unmerged blank cell
If br Is Nothing Then
Set br = r
Else
Set br = Union(br, r)
End If
End If
Next r
Debug.Print "blank cells: " & br.Address(0, 0)
End Sub

excel vba loop thru range and copy to single cell

I am trying to do a loop with Excel VBA, I have a data range in a1:a1000, I want to loop through them and copy one by one to single cell of C1, but below code not working, any idea what went wrong?
Dim I As Integer
For I = 1 To lastrow - 1
Sheets("display").Range("w1").Value = Sheets("data").Range("c1").Offset(I, 0).Value
msgbox Sheets("data").Range("c1").Value
Next I
You're setting the value in cell "W1" instead of "C1".
Updated After Author's Clarification of Question:
Below are two ways you can loop through cells and copy/paste. Neither one is "better". I would like to emphasize that there are probably more efficient methods than these to accomplish your task, but hopefully this answer gets you a resolution.
Sub LoopExampleUsingRange()
Dim aCell As Range
For Each aCell In Range("A1:A1000").Cells
aCell.Copy Range("C1")
Next aCell
End Sub
Sub LoopExampleUsingIntegerReference()
Dim i As Integer
For i = 1 To 1000
Range("A" & i).Copy Range("C1")
'I prefer to use offset, but they both work:
'Range("A1").Offset(i - 1, 0).Copy Range("C1")
Next i
End Sub

How to resize a range to stop at a cell with text VBA?

I'm trying to resize a range to start at a certain point and resize it down until it hits a cell that contains the text "End of Data"
What would that/those line(s) of code look like? I don't know if you can pass a string find argument to the resize function for range.
Thank you!
These examples assume you're working in column A.
If you don't have any blank cells until the end of your data, you can simply perform the VBA equivalent of pressing Ctrl-Shift-DownArrow:
Range(Range("A1"),Range("A1").End(xlDown)).Select
Otherwise you'll need to first find the cell using a loop or the find function. Looping is a little slower but easier to code:
i = 0
Do
i = i + 1
Loop While Cells(i, 1) <> "End of Data"
Range("A1", Cells(i, 1)).Select
The following guide is good for explaining the various ways to refer to a range of data in VBA:
https://msdn.microsoft.com/en-us/library/office/gg192736(v=office.14).aspx
you could use this function:
Function ResizeRangeDownToACertainString(iniCell As Range, stringToStopAt As String) As Range
Dim endCell As Range
With iniCell.Parent
Set endCell = .Range(iniCell, .Cells(.Rows.count, iniCell.Column)).Find(what:=stringToStopAt, LookIn:=xlValues, lookat:=xlWhole)
If endCell Is Nothing Then
Set ResizeRangeDownToACertainString = iniCell
Else
Set ResizeRangeDownToACertainString = .Range(iniCell, endCell)
End If
End With
End Function
and exploit it in your "main" code as follows
Sub main()
Dim myRng As Range
Set myRng = ResizeRangeDownToACertainString(Range("A2"), "End Of Data")
End Sub
you may want to change the function behavior when it doesn't find the wanted string

How to Set a Range outside a Loop and use it inside

Î've read lots of questions recommanding me to avoid using Select. So I've tried to set a target cell but I've met a problem:
I want to use a For Loop to fill a table, but the target cell will change each time with the Loop going on. For example:
Sub try()
Dim target As Range
Set target = Worksheets("Data").Cells(i, 1)
For i = 1 To 10
target.Value = i
Next i
End Sub
So can I use a Range in Loop or not?
If I set the target in the For Loop, I'm afraid it will not be faster than I choose directly the cell Worksheets("Data").Cells(i, 1)in the Loop? Because I'll actually have lots of targets to use, so I wish to find a easier method to set the targets and fill them everytime without setting them one by one.
Sorry if I've post a duplicate question because I didn't find a similar question or an answer on the net. If you've got an idea, please leave a comment. Thank you!
Based on your comment about "reading" each line. This code uses a For Each and examines each cell to see what to do.
Public Sub Test()
Dim rMyRange As Range
Dim rCell As Range
'Define a range on the same sheet.
Set rMyRange = ThisWorkbook.Worksheets("Sheet1").Range("A1:A15,C1:C20,D18,E19:E20")
'Add another range using Union just for the hell of it.
Set rMyRange = Union(rMyRange, ThisWorkbook.Worksheets("Sheet1").Range("F30"))
'Step through each cell in rMyRange and decide what to do based on contents/formatting of cell.
For Each rCell In rMyRange
If rCell = "Colour" Then 'Value is default property.
rCell.Interior.Color = RGB(255, 0, 0)
Else
Select Case rCell.Font.Color
Case 255 'Red
rCell = "Red"
Case 5287936 'Green
rCell = "Green"
Case Else
rCell = "Some Other Colour"
End Select
End If
Next rCell
End Sub

Resources