Looking for text in a range with vba - vba

I have a range that contains different words in different columns the range would be DT21:EH400. I want to know if there is a way to search through that range and if there is a word copy and paste it to the same row it is on but in column B.

The built in Find functionality should be quicker than writing your own loop:
Sub findUsingFIND()
Dim searchString As String
searchString = Excel.Application.InputBox("Enter string please")
Dim targetArea As Range
Set targetArea = Excel.Application.InputBox("Select range to search", , , , , , , 8)
targetArea.Select
'Excel.ThisWorkbook.Sheets(1).Range("DT21:EH400").Select
Dim foundRange As Range
With targetArea
Set foundRange = _
.Find(What:=searchString, _
After:=.Cells(1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
End With
If Not foundRange Is Nothing Then
ThisWorkbook.Sheets(1).Range("B" & foundRange.Row) = searchString
Else
MsgBox "Nothing found"
End If
End Sub
If there are several instances of the string then the above can be adapted to the following:
Sub findSeveralUsingFIND()
Dim searchString As String
searchString = Excel.Application.InputBox("Enter string please")
Dim targetArea As Range
Set targetArea = Excel.Application.InputBox("Select range to search", , , , , , , 8)
targetArea.Select
'Excel.ThisWorkbook.Sheets(1).Range("DT21:EH400").Select
Dim foundRange As Range
With targetArea
Set foundRange = _
.Find(What:=searchString, _
After:=.Cells(1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not foundRange Is Nothing Then
FirstAddress = foundRange.Address
Do
ThisWorkbook.Sheets(1).Range("B" & foundRange.Row).Value = searchString
Set foundRange = .FindNext(foundRange)
Loop While Not foundRange Is Nothing And foundRange.Address <> FirstAddress
Else
MsgBox "Nothing found"
End If
End With
End Sub
As #ChrisNeilsen points out there is a very fast method that would be preferable if you need to perform your search many times. This uses arrays. My understanding is relatively shallow as to why this approach is quick but I believe it is in connection with the way arrays store the data in a block of memory addresses that are next to each other. Here is a good comparison of different approaches:
http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/
Here is the macro using an array of variant type:
Sub findUsingVARARRAY()
Dim vArr As Variant, vRes As Variant
Dim j As Long
Dim n As Long
Dim searchString As String
searchString = Excel.Application.InputBox("Enter string please")
Dim targetArea As Range
Set targetArea = _
Excel.Application.InputBox(prompt:="Select range to search", Type:=8)
Dim firstRow As Long
vArr = targetArea.Value2
ReDim vRes(LBound(vArr, 1) To UBound(vArr, 1), 1 To 1)
Dim r As Long, c As Long
For r = LBound(vArr, 1) To UBound(vArr, 1)
For c = LBound(vArr, 2) To UBound(vArr, 2)
' use vbTextCompare for case insenstitive comapre
' use vbBinaryCompare for case senstitive comapre
If StrComp(vArr(r, c), searchString, vbTextCompare) = 0 Then
vRes(r, 1) = searchString
Exit For
End If
Next c, r
targetArea.EntireRow.Columns(2) = vRes
End Sub

The following code may work
It searches for the word in the range and sets the search word as a value in column B of the row where the search word was found
Dim strSearch as String
Dim rngData as Range
Dim rngCell as Range
strSearch = "Word to Search"
Set rngData = Range(Cells(21,124),Cells(400,138))
For each rngCell in rngData
If rngCell.value = strSearch Then
cells(rngcell.Row, 2).Value = strSearch
End if
Next rngCell

Related

finding the first and last entry with a certain value in a row

I have a excel sheet containing multiple cells with a string foo in the first row. I want to find the first and last column in which the string is written. I have tried the following
Dim first_col As Integer
Dim last_col As Integer
Dim col As Integer
Dim found As Range
Dim ws_MLB as Worksheet
Dim foo as String
set ws_MLB = ThisWorkbook.Sheet(1)
Set found = ws_MLB.Rows(1).Find(foo)
If Not found Is Nothing Then
col = found.Column
first_col = col
last_col = col
Do
found = ws_MLB.Rows(1).FindNext(found)
col = found.Column
If col < first_col Then
first_col = col
MsgBox ("This should not happen")
ElseIf col > last_col Then
last_col = col
End If
Loop While Not found Is Nothing And col <> first_col
Else
MsgBox ("not found")
End If
But this way I only get the the first value for both first_col and last_col. When I search for the string with the integrated excel search I find multiple instances. So the string is there. Have I done a mistake or is there a better way to do this?
edit forgot to mention that I also tried to change the search direction, but I still got the first entry.
You can make this a lot easier by using the SearchDirection Parameter in .Find by using xlNext you search Left to Right then xlPrevious searches Right to Left.
Sub FindFL()
Dim wbk As Workbook
Dim ws As Worksheet
Dim fColumn As Long, lColumn As Long
Set wbk = ThisWorkbook 'Change this to your workbook
Set ws = wbk.Worksheets("Sheet1") 'Change this to your worksheet
With ws
'Find first column that foo shows up
fColumn = .Cells.Find(What:="foo", _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=False).Column
'Find last column that foo shows up
lColumn = .Cells.Find(What:="foo", _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
Debug.Print "First Column is " & fColumn; vbNewLine _
; "Last Column is " & lColumn
End With
End Sub
I would do that like this:
Public Sub foo()
Dim nCol As Integer
Dim nFirst As Integer
Dim nLast As Integer
With ActiveSheet
nCol = 1
Do Until .Cells(1, nCol) = ""
If .Cells(1, nCol) = "foo" Then
If nFirst = 0 Then
nFirst = nCol
Else
nLast = nCol
End If
End If
nCol = nCol + 1
Loop
End With
MsgBox "First: " & nFirst & vbCr & "Last: " & nLast
End Sub

Modify macro for column search

I have a macro that until now was used just to search one cell from column F but now I must search for all the cell in column F. If value from F is found in range N:AN, offset(f,0,1) must have the cell value (found row , column AI).
Sub find()
Dim FindString As String
Dim Rng As Range
FindString = Sheets("Sheet1").Range("f48").Value
If Trim(FindString) <> "" Then
With Sheets("Sheet1").Range("n:an")
Set Rng = .find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Sheets("Sheet1").Range("f48").Offset(0, 1).Value = Rng.Offset(0, 21).Value
Else
Sheets("Sheet1").Range("f48").Offset(0, 1).Value = "Nothing found"
End If
End With
End If
End Sub
Perhaps this, if I understand correctly (it does assume the value in F will only be found once at most).
Sub find()
Dim Rng As Range
Dim r As Range
With Sheets("Sheet1")
For Each r In .Range("F1", .Range("F" & .Rows.Count).End(xlUp))
If Trim(r) <> vbNullString Then
With .Range("n:an")
Set Rng = .find(What:=r.Value, _
LookAt:=xlWhole, _
MatchCase:=False)
If Not Rng Is Nothing Then
r.Offset(0, 1).Value = .Cells(Rng.Row, "AI").Value
'Else
' Sheets("Sheet1").Range("f48").Offset(0, 1).Value = "Nothing found"
End If
End With
End If
Next r
End With
End Sub
See if this is helpful. Its a bit of a change but I think it may be cleaner :)
Of course you need to adjust it for your offset criteria once you "find" a match in the N:NA range
Sub Dougsloop()
Dim rCell As Range
Dim rRng As Range
Dim wsO As Worksheet
Dim aRR As Variant
Set wsO = ThisWorkbook.Sheets("Sheet1")
aRR = wsO.UsedRange.Columns("N:NA")
Set rRng = ThisWorkbook.Sheets("Sheet1").Range("F1:F500")
For Each rCell In rRng.Cells
If Trim(rCell.Value) <> vbNullString Then
thisValue = rCell.Value
If IsError(Application.Match(aRR, thisValue, 0)) = True Then
'Generic Eror Handling
ElseIf IsError(Application.Match(aRR, thisValue, 0)) = False Then
'Stuff you do when you find the match
rCell.Offset(0, 1).Value = "found it"
End If
End If
Next rCell
End Sub

Excel VBA: What am I missing in this simple OFFSET?

Code finds the header row and correct column. I want to execute some code on the range starting one cell under the header row in the same column and down to the last row in the same column. I've tried to use offset to create the range but the offset fails every time. Can offset not be used this way?
Sub Del_Y_Rows()
Dim Rng, fcell, LastRow, SrchRng, sRNG, eRNG As Range
Dim Findstring As String
Findstring = "Header"
With Sheets("thisSheet")
Set SrchRng = .Range("a1:l15")
Set fcell = SrchRng.Find(What:=Findstring, _
LookAt:=xlWhole, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
MatchCase:=False)
LastRow = .Cells(Rows.Count, fcell.Column - 2).End(xlUp).Row
Debug.Print "fcell " & fcell.Address
sRNG = .Range(fcell).Offset(1, 0) 'this fails 'sRng = start of the range
Debug.Print "srng " & sRNG
eRng = .cells(LastRow, fcell.Column) 'eRng = end of the range
Rng = .Range(sRNG, eRng)
Debug.Print "rng is " & Rng.Address
End With
End Sub
fcell is a range and the RAnge() is not needed:
sRNG = fcell.Offset(1, 0)
One more thing, You will want to use a check to make sure the fcell is actually a range and not nothing.
Sub Del_Y_Rows()
Dim Rng As Range, fcell As Range, LastRow as Long , SrchRng As Range, sRNG As Range, eRNG As Range
Dim Findstring As String
Findstring = "Header"
With Sheets("thisSheet")
Set SrchRng = .Range("a1:l15")
Set fcell = SrchRng.Find(What:=Findstring, _
LookAt:=xlWhole, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
MatchCase:=False)
LastRow = .Cells(Rows.Count, fcell.Column - 2).End(xlUp).Row
If not fcell is nothing then
Debug.Print "fcell " & fcell.Address
set sRNG = fcell.Offset(1, 0) 'this fails 'sRng = start of the range
Debug.Print "srng " & sRNG
set eRng = .cells(LastRow, fcell.Column) 'eRng = end of the range
set Rng = .Range(sRNG, eRng)
Debug.Print "rng is " & Rng.Address
End If
End With
End Sub
You must use Set for objects.
Set sRNG = .Range(fcell).Offset(1, 0)

VBA: Search, save and replace by rows according to conditions

I have an input like this:
gen,N,,,GONGD,,,N,,,KL,0007bd,,,,,,,,TAK,
gen,N,,,RATEC,,,N,,,KP,0007bc,,,,,,,,TAZ,
kap,N,,,EBFWE,N,,,,,,,,,KP,002bd4,,,KP,123000,,,,,N,,,,P
kap,N,,,ST,WEIT,E3,EBFWEI,,,KP,002bd2,N,,,,,,KP,002bd3,,,,,,,Z,MG00,,,,,N,,,,P
I have a code like this:
Sub Find()
Dim rFoundAddress As Range
Dim sFirstAddress As String
Dim x As Long
With ThisWorkbook.Worksheets("Sheet1").Columns(1)
Set rFoundAddress = .Find("kap,*", LookIn:=xlValues, LookAt:=xlWhole)
If Not rFoundAddress Is Nothing Then
sFirstAddress = rFoundAddress.Address
Do
Dim WrdArray() As String
Dim text_string As String
Dim i As String
Dim k As String
Dim num As Long
text_string = rFoundAddress
WrdArray() = Split(text_string, "KP,")
i = Left(WrdArray(1), 6)
k = Left(WrdArray(2), 6)
Columns("A").Replace What:=i, _
Replacement:=k, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Set rFoundAddress = .FindNext(rFoundAddress)
Loop While Not rFoundAddress Is Nothing And _
rFoundAddress.Address <> sFirstAddress
End If
End With
End Sub
What I am trying to do:
Find all lines starting with "kap" and save 6 chars/int after first "KP" as i and 6 chars/int after second "KP" as k. Then search the whole data-set (hundreds of rows in column A) if they contain string i and if yes, then replace it for string k. And to loop this. So it will do the same with another line starting with "kap". The code gives me error message: Subscript out of range when it comes to "Columns("A")..." for the second time. Can you help me please?
THANK YOU IN ADVANCE
edited to make all searched string occurrences the same ("kap,*")
you don't want to modify (via Replace()) the range you're looping through
so collect all needed replacements in an array while looping through the range and then loop through the array and make the replacements
like follows:
Option Explicit
Sub Find()
Dim rFound As Range
Dim sFirstAddress As String
Dim val As Variant
Dim nKap As Long
With ThisWorkbook.Worksheets("Sheet1").Columns(1)
nKap = Application.WorksheetFunction.CountIf(.Cells, "kap,*") '<--| count the occurrences of "kap,*"
If nKap > 0 Then
ReDim vals(1 To nKap) As Variant '<--| array that will collect all find/replace couples
nKap = 0
Set rFound = .Find("kap,*", LookIn:=xlValues, LookAt:=xlWhole)
sFirstAddress = rFound.Address
Do
nKap = nKap + 1
vals(nKap) = Split(Split(Split(rFound.text, "KP")(1), ",")(1) & "," & Split(Split(rFound.text, "KP")(2), ",")(1), ",") '<--| store the ith couple of find/replace values
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
For Each val In vals '<--| loop through values to be replaced array
.Replace What:=val(0), _
Replacement:=val(1), _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Next val
End If
End With
End Sub
Function GetValues(txt As String) As Variant
If InStr(txt, "KP") > 0 Then GetValues = Split(Split(Split(txt, "KP")(1), ",")(1) & "," & Split(Split(txt, "KP")(2), ",")(1), ",")
End Function

VBA Code to Search Text

I want to amend the code below
I want the findwhat to pick text from a range ("a1:20")-which contains the list of text i want to look for
If it finds the text in the description in B, i want it to return the text it found e.g jo IN range c beside its description
Thanks
Option Explicit
Sub x()
Dim FindWhat, rngCell As Range, i As Integer
FindWhat = Array("Jo", "oa", "of", "koo")
For i = 0 To 3
For Each rngCell In Range("B2", Range("B" & Rows.Count).End(xlUp))
If InStr(rngCell, FindWhat(i)) <> 0 Then
rngCell.Offset(0, 1) = rngCell
rngCell.Offset(, 1).Resize(, 2).Copy
End If
Next rngCell
Next i
End Sub
Try this:
Option Explicit
Sub x()
Dim findRng As Range, _
targetRng As Range, _
findCell As Range, _
found As Range
Dim i As Integer
Dim firstFound As String, _
columnName As String
columnName = "B"
Set findRng = Range("A1:A20")
For Each findCell In findRng
Set targetRng = Range(columnName & "2", Range(columnName & Rows.Count).End(xlUp))
With targetRng
Set found = .Find(findCell.Value, LookIn:=xlValues, lookat:=xlPart)
If Not found Is Nothing Then
firstFound = found.Address
Do
found.Offset(0, 1).Value = found.Offset(0, 1).Value & findCell.Value & ", "
Set found = .FindNext(found)
Loop While Not found Is Nothing And found.Address <> firstFound
End If
End With
Next findCell
End Sub
Note that unless what you're doing is a little more complex than this, you can achieve this result using cell formulae. Read the help on the Index, Match and VLookup functions to see how to achieve this.