Find and replace multiple values in Excel using VBA - vba

I'm looking for VBA code to run in Excel to find and replace lots of words.
Basically, it will be a simple Excel file where Sheet1 contains phrases in 1 column which contains names to be replaced (not the whole phrase but one name which might consist of few words). Second sheet2 contains in 1 column values which I need to find in Sheet1 (there might be more than one time when value appears to be found in 1st column) and column which contains translation. I don't need Google API for this because names are very custom.
I came across to the following script but it does nothing basically.
Sub ReplaceValues()
Dim dataSht As Worksheet
Dim editSht As Worksheet
Dim dataRange As Range
Dim dataColumn As Long
Dim editColumn As Long
Dim dataEndRow As Long
Dim editEndRow As Long
'sheet that holds all the values we want to find
Set dataSht = Sheet2
'sheet we want to edit
Set editSht = Sheet1
Dim replaceValue As String
'replace value is empty string
replaceValue = ""
'set the column of the data sheet to A
dataColumn = 1
'set the colmun of the sheet to edit to A
editColumn = 5
dataEndRow = dataSht.Cells(dataSht.Rows.count, dataColumn).End(xlUp).Row
editEndRow = editSht.Cells(editSht.Rows.count, editColumn).End(xlUp).Row
'this is the range of the data that we're looking for
Set dataRange = dataSht.Range(dataSht.Cells(1, dataColumn),
dataSht.Cells(dataEndRow, dataColumn))
Dim count As Long
Dim val As String
For i = 1 To editEndRow
val = editSht.Cells(i, editColumn).Value
count = Application.WorksheetFunction.CountIf(dataRange, val)
If count > 0 And Trim(val) <> "" Then
editSht.Cells(i, editColumn).Value = replaceValue
End If
Next i
End Sub

Finally, I was able to do what I need with a very simple piece of code. Get trained folks!
Sub Test()
Dim Sh1 As Worksheet
Dim Sh2 As Worksheet
Dim FndList, x&
Set Sh1 = Sheets(1)
Set Sh2 = Sheets(2)
FndList = Sh2.Cells(1, 1).CurrentRegion
For x = 1 To UBound(FndList)
Sh1.Cells.Replace What:=FndList(x, 1), Replacement:=FndList(x, 2), LookAt:=xlPart
Next
End Sub

So as I understand correctly you want a list of phrases translated by a dictionary - word by word. The following script should do it - assuming Sheet1 contains the phrases (in column 1 from row 2) and Sheet2 contains the dictionary(column1 for original values, column2 for translations and also from row2 on). The replaced/translated phrases will appear in column2 of Sheet1.
Firstly, in your original code, vba will take Sheet1 and Sheet2 as two undefined variable automatically, hence there's no alert about this. You should use Worksheets() collection to specify the worksheet.
Secondly, you forgot to change the value of replaceValue. Actually, you can put the cell.value into the replace function as a parameter directly. Therefore there is no need to set a variable for this unless you want to make it more readable.
Lastly, if you want to check whether a word is contained or not. Use InStr function. However in your case, using a replace function is good enough. It will replace the word into the translation you wanted, and will do nothing if there is no match to be found.
Sub btn_Click()
Dim cntPhrases As Integer
Dim cntDict As Integer
Worksheets("Sheet1").Activate
cntPhrases = Worksheets("Sheet1").Range("A:A").Cells.SpecialCells(xlCellTypeConstants).Count - 1
cntDict = Worksheets("Sheet2").Range("A:A").Cells.SpecialCells(xlCellTypeConstants).Count - 1
MsgBox (cntPhrases)
Dim i As Integer
Dim j As Integer
Dim phrase As String
Dim org As String
Dim rep As String
For i = 2 To cntPhrases + 1
phrase = Cells(i, 1)
For j = 2 To cntDict + 1
org = Worksheets("Sheet2").Cells(j, 1)
rep = Worksheets("Sheet2").Cells(j, 2)
phrase = replace(phrase, org, rep)
Next j
Cells(i, 2) = phrase
Next i
End Sub

You could also do it like this.
Sub main()
Dim Find_text() As String
Dim Replace_text() As String
Dim str As String
str = "test 150 test 160 test 170 test 200 test 220"
Find_text = Split("150 160 170 180 190 200 210 220")
Replace_text = Split("15 16 17 18 19 20 21 22")
For i = 0 To UBound(Find_text)
For j = 0 To UBound(Replace_text)
If InStr(str, Find_text(j)) > 0 Then
str = Replace(str, Find_text(j), Replace_text(j))
End If
Next
Next
MsgBox str
End Sub

Related

Find the texts in Dynamic Range in another sheet

I am creating a VBA application that will find the text that I have entered in a certain range (Should be dynamic, in order for me to input more in the future). With that the entered texts in the range will look for the words in another sheet column:
Example:
And it will look for the words inputted in another sheet.
Dim Main as Worksheet
Set Main = Sheets("Sheet1")
Dim Raw2 as Worksheet
Set Raw2 = Sheets("Sheet2")
LookFor = Main.Range(D8:100)
Fruits = Raw2.Range("G" & Raw2.Rows.Count).End(xlUp).row
For e = lastRow To 2 Step -1
value = Raw2.Cells(e, 7).value
If Instr(value, LookFor) = 0 _
Then
Raw2.Rows(e).Delete
Honestly I am not sure how to proceed. And the mentioned code is just experiment. Desired output is to delete anything in sheet2 except for the rows that contain the words that I have inputted in the "Look for the words". Hope you can help me. Thank you.
This should do the trick :
Sub Sevpoint()
Dim Main As Worksheet
Set Main = Sheets("Sheet1")
Dim Raw2 As Worksheet
Set Raw2 = Sheets("Sheet2")
Dim LooKFoR() As Variant
Dim LastRow As Double
Dim i As Double
Dim j As Double
Dim ValRow As String
Dim DelRow As Boolean
LooKFoR = Main.Range(Main.Range("G8"), Main.Range("G" & Main.Rows.Count).End(xlUp)).Value
LastRow = Raw2.Range("G" & Raw2.Rows.Count).End(xlUp).Row
For i = LastRow To 2 Step -1
ValRow = Raw2.Cells(i, 7).Value
DelRow = True
'MsgBox UBound(LooKFoR, 1)
For j = LBound(LooKFoR, 1) To UBound(LooKFoR, 1)
If LCase(ValRow)<>LCase(LooKFoR(j, 1)) Then
Else
DelRow = False
Exit For
End If
Next j
If DelRow Then Raw2.Rows(i).Delete
Next i
End Sub

Transporting text from one worksheet to another with two Dynamic ranges- VBA Excel

I have two worksheets (one for input and another for output) and I'm trying to copy some information on cells along a row from the input to cells along a row on the output. My code stops if, on a separated list of ranges, there's no info. The code I'm using is like that right now:
Sub Txt_Manobra()
Dim x As Range
Dim i As Integer
Dim o As Integer
Dim p As Integer
Dim Txt1 As String
Dim Txt2 As Variant
For Each x In Worksheets("Formulario").Range("AK9:AK47").Cells
If x.Value <> "" Then Txt1 = x.Value
o = 8 + x.Count
For i = 1 To 7
p = 3 + i
Txt2 = Worksheets("Formulario").Range(o, p).Value
Worksheets("SdB pg1").Range(Txt1).Cells(1, i) = Txt2
Next i
Next x
End Sub
For each range value (x), it looks on the range txt1 (That is composed of only one row), and it should copy the values on range (D9:J9), one at a time and put on the range determined x (also only one row and with the same number of columns as D9:J9) then look on the next row (D10:J10) and so on.
I'm getting errors and I think this might be easier to do than I Think.
It's like that:
Input
And I want to tranfer to
Output
Each cell in the range "AK9:AK47" Contains a range like "P10:V10"
I haven't made it to work out to see if my "o" changes
If there are valid cell addresses in range AK9:AK47, then something like this should work for you. Note that using single letter variables is bad practice, and you can customize the code by adjusting the constants at the top.
Sub tgr()
Const sDestInfoCol As String = "AK"
Const lHeaderRow As Long = 8
Const lStartCopyCol As String = "D"
Const lFinalCopyCol As String = "J"
Dim wb As Workbook
Dim wsData As Worksheet
Dim wsDest As Worksheet
Dim rDestInfo As Range
Dim rDestTemp As Range
Dim lNumCols As Long
Set wb = ActiveWorkbook
Set wsData = wb.Sheets("Formulario")
Set wsDest = wb.Sheets("SdB pg1")
Set rDestInfo = wsData.Range(sDestInfoCol & lHeaderRow + 1, wsData.Cells(wsData.Rows.Count, sDestInfoCol).End(xlUp))
If rDestInfo.Row <= lHeaderRow Then Exit Sub 'No data
lNumCols = Columns(lFinalCopyCol).Column - Columns(lStartCopyCol).Column + 1
For Each rDestTemp In rDestInfo.Cells
With rDestTemp
If Evaluate("ISREF(" & .Text & ")") Then
wsDest.Range(.Text).Resize(1, lNumCols).Value = wsData.Cells(.Row, lStartCopyCol).Resize(1, lNumCols).Value
End If
End With
Next rDestTemp
End Sub

Going through workbook and making a column in the first sheet out of the content of a particular cell across all sheets

This gives me an error:
(Constant expression required)
Code:
Dim Sheet3 As Worksheet
Dim t As Long
Dim Max As Long
Max = ActiveWorkbook.Worksheets.Count
Dim Dates(2 To Max) As String
For t = 2 To ActiveWorkbook.Worksheets.Count
Set Sheet3 = ActiveWorkbook.Worksheets(t)
If Sheet3.Name = "USA" & t Then
Dates(t) = Sheet3.Range("E4").Value
End If
Next t
Dim SummarySheet as Sheet
For r = 2 To ActiveWorkbook.Worksheets.Count
Set Sheet = ActiveWorkbook.Worksheets(r)
If Sheet.Name = "Page"& r Then
SummarySheet.Cells(Row you want to paste,Column you want to paste) = Sheet.Range("Cell you want to copy").Value
End if
Next r
I was in doubt if your t and r were different, but if so then you should make a For loop for both, or make r a calculated value from t
Edit: If you want to paste in H9 and go from there, you column will be 8 and your row 9. If you then put 9+r it will always take the next row below. Assuming r starts at 1 and has all number in a row. You can play a bit with these values until you get it right.
SomeVariable = Sheet.Range("B22").Value
If you need a way to iterate the sheets you can do this.
iFoundWorksheet = 0
For iIndex = 1 To ea.ActiveWorkbook.Worksheets.Count
Set ws = ea.Worksheets(iIndex)
If UCase(ws.Name) = "RESULTS" Then
iFoundWorksheet = iIndex
Exit For
End If
Next iIndex
If iFoundWorksheet = 0 Then
MsgBox "No worksheet was found with the name RESULTS (this is not case sensetive). Aborting."
GoTo Abort
End If
Set ws = ea.Worksheets(iFoundWorksheet)
ws.Activate
For you new issue Constant expression required
Your array definition has to be defined with constants.
Dim Max As Long
Const Max1 = 5
Dim Dates(2 To Max1) As String
This would work. But you are not going to be able to load
ActiveWorkbook.Worksheets.Count
Into a const
You are probably going to need to ReDim your Dates Array.

Excel range to plane string

I am trying to read an Excel range to a variable of type string.
Currently I have achieved it with a work around. I copied the range to clipboard and used a ReadClipBoard function that reads the clipboard as assigns to variable. This method is not efficient and also some times it gives error due to clipboard issues with VBA.
Workaround Code:
Dim variable as string
Range("A1:C5").Copy
variable = ReadClipBoard()'Function that returns clipboard text
Is there a better way to do it?
This will turn each line into a tab-separated string and the whole range into a line-separated string.
Public Function RangeToText(ByRef r As Range)
Dim vaData As Variant
Dim aOutput() As String
Dim i As Long
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
'Put range into a two dim array
vaData = r.Value
'Make one dim array the same number of rows
ReDim aOutput(1 To UBound(vaData, 1))
'Make strings With tabs out of each row
'and put into one dim array
For i = LBound(vaData, 1) To UBound(vaData, 1)
aOutput(i) = Join(wf.Index(vaData, i), vbTab)
Next i
'join all the strings into one multi-line string
RangeToText = Join(aOutput, vbNewLine)
End Function
In the Immediate Window
?rangetotext(sheet1.Range("A1:C5"))
Here Here Here
is is is
some some some
column 1 column 2 column 3
text text text
The Index worksheet function is used to process only one row at a time because Join requires a one dimensional array
If you are reading more than once cell, then the variable would be an array For example:
Sub ArrayDemo()
Dim r As Range
Set r = Range("A1:C5")
variable = r
End Sub
is nearly equivalent to :
Sub ArrayDemo2()
Dim r As Range
Set r = Range("A1:C5")
Dim variable(1 To 5, 1 To 3) As Variant
For i = 1 To 5
For j = 1 To 3
variable(i, j) = Cells(i, j).Value
Next j
Next i
End Sub
Naive way is to concatenate all the content into a string, is that ok for you?
Function ConcatCells(r as range, optional sep as string) as string
dim c as range
dim s as string
s=""
if sep is missing then sep=" "
for each c in r.cells
s = s & c & sep
next c
s=left(s, len(s) - len(sep))
ConcatCells=s
end sub

Match in two different sheet and offset

I am writing the following code that finds a match from one worksheet (Sheet2) and pastes values into (sheet2).
So far the code targets those names that have "accepted" as offset values. it loops through looking for a match and displaying it. However i would like to also select the offset values and paste them in sheet1 if possible. THis is where I am getting confused please help, where to take my code from here?
Sheet1
Column a , b
5 Jim Accepted
6 Bob Rejected
7 Tim Accepted
Sheet 2
Column d e f g
Jim 40 0.4
Bob 78 58
Tim 36 45
Sub check()
Dim i As Long, lastrow As Long, myval As Long
Dim agentname As String
Dim sh2 As Worksheet
Dim val As String
Dim findstr As String
Dim rng As Range
Set sh2 = Sheets(2)
lastrow = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To lastrow
agentname = Cells(i, 1).Offset(, 1).Value
If Cells(i, 1) = "Accepted" And Not IsEmpty(Cells(i, 1)) Then
'For i = 1 To sh2.Range("b2:b9")
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("b1:b9"), 0)
findstr = agentname
MsgBox agentname
End If
Next i
End Sub
Few problems -
agentname = Cells(i, 1).Offset(, 1).Value
This appears to be looking in the wrong column. It's returning "Accepted" or "Rejected" instead of the name. So remove the offset - you can specify what column you want directly, no need to offset. Keep it simple. (You don't even need the .Value, it's assumed)
agentname = Cells(i,1)
Now this is doubly confusing--
If Cells(i, 1) = "Accepted" And Not IsEmpty(Cells(i, 1)) Then
Again referring to the wrong column, we want column 2 here. And beyond that, if it is 'accepted', how could it also be empy? So we want:
If Cells(i, 2) = "Accepted" then
Ok, so next -
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("b1:b9"), 0)
What is myval? Not a descriptive name, that can confuse you when you come back to your code. You're trying to match the agent name you saved, and specifying the range and sheet is on, that's great. Are the names really in column B? Without knowing the exact layout i'll assume they're on sheet 2 column A instead, that's easier for me. So now it's working when it finds a name, but a weird function of Worksheetfunction means it'll break if it can't find anything. So we'll wrap it in some error handling.
On Error Resume Next
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("A1:A9"), 0)
If Err = 0 Then
findstr = agentname
MsgBox agentname
End If
On Error GoTo 0
I'm a little short on time, so a few more comments-
1.) You named your worksheet2 , that's fantastic. You should do it for worksheet1 too. In fact, go further and specify the workbook too. It'll save a lot of headache.
2.) You need to indent properly, maybe it just messed up when you posted here but those For loops and If statements need to be indented or you'll get a headache the next time you try to figure out what you were doing
3.) Use descriptive names, especially if you're writing a longer script that does a lot of things like this one.
4.) This is an opinion, but I think you should wait to declare your variables until you're about to use them. Again increased readibility. (And look into camel-Case for naming your variables, it's cosmetic, but...anyway I think it looks better)
Setup I was using - Sheet1:
A B
Tim Accepted
Tom Rejected
Sheet2:
A B C
Tim 40 30.1
Tom 21 15.5
Jeff 18 31.3
Code:
Sub check()
Dim sh1 As Worksheet: Dim sh2 As Worksheet
Set sh1 = Sheets(1)
Set sh2 = Sheets(2)
Dim val As String
Dim findstr As String
Dim lastrow As Long
lastrow = sh1.Cells(Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 1 To lastrow
Dim agentname As String
agentname = sh1.Cells(i, 1)
If sh1.Cells(i, 2) = "Accepted" Then
On Error Resume Next
Dim myval As String
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("A1:A9"), 0)
If Err = 0 Then
findstr = agentname
MsgBox agentname
End If
On Error GoTo 0
End If
Next i
End Sub
Instead of matching i have used the vlookup function this return the value in sheet2 matching the name on sheet1. This provides the basics of what I was trying to achieve. The code Acantud provided laid the foundation
Sub check()
Dim sh1 As Worksheet: Dim sh2 As Worksheet
Set sh1 = Sheets(1)
Set sh2 = Sheets(2)
Dim val As String
Dim findstr As String
Dim lastrow As Long
lastrow = sh1.Cells(Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 1 To lastrow
Dim agentname As String
agentname = sh1.Cells(i, 1)
If sh1.Cells(i, 2) = "Accepted" Then
On Error Resume Next
Dim myval As String
Dim myval1 As String
myval = Application.WorksheetFunction.VLookup(agentname, sh2.Range("A1:E13"), 3, False)
myval1 = Application.WorksheetFunction.VLookup(agentname, sh2.Range("A1:E13"), 5, False)
'Application.WorksheetFunction.Match(agentname, sh2.Range("A1:A9"), 0)
sh1.Cells(i, 3) = myval
' sh1.Cells(i, 4) = myval1
If Err = 0 Then
findstr = myval
End If
On Error GoTo 0
End If
Next i
End Sub