I'm working on a macro and I want to record an addon to the below code:
Selection.Replace What:="<", replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False, FormulaVersion:=xlReplaceFormula2
New code needed: if the above ended up replacing <, then the cell needs to be marked in yellow (colorindex=6). Which code would allow me to do this?
You can use replace to replace the format
Dim ReplaceRange As Range
Set ReplaceRange = Selection
'define color for ReplaceFormat
With Application.ReplaceFormat.Interior
.ColorIndex = 6
End With
'replace the format and text
ReplaceRange.Replace What:="<", replacement:=vbEmpty, LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=True, FormulaVersion:=xlReplaceFormula2
Hi I am new to this Excel VBA , I am getting a runtime compilation error in the following Macro -
ActiveCell.FormulaR1C1 = "EmployeeID"
ActiveCell.Offset(0, 1).Columns("A:A").EntireColumn.Select
Selection.Replace What:="0", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Selection.Replace What:="1", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Selection.Replace What:="2", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
ActiveCell.Offset(0, -1).Columns("A:A").EntireColumn.Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=ActiveCell. _
Offset(-1,0).Range("A:A"), SortOn:=xlSortOnValues, Order:=xlAscending,
DataOption:=xlSortNormal
Please help me with the error in the code.
Thanks
You're getting a compile error, not a run-time error. Compilation errors are the VBA compiler saying "I don't know what this is saying, I can't run it"; run-time errors happen when the code compiles and runs, and then suddenly blows up and you're in break mode and need to debug to resume execution.
The macro recorder has a tendency to "inject" line continuation tokens to split up long member calls into multiple "physical lines"; in VBA line continuations can make a "logical" line of code span up to 20 "physical" lines in the source code file.
The token is defined as a space followed by an underscore, then a new line.
The problem is that the recorder will break up an instruction anywhere it's legal to do so, without regards to readability: it's not rare for it to split up named arguments at the := operator, and in the current case we have a member call (Range.Offset) separated from its qualifying dot (ActiveCell.).
First thing to do when cleaning up macro recorder code, is to get rid of all the line continuations.
ActiveCell.FormulaR1C1 = "EmployeeID"
ActiveCell.Offset(0, 1).Columns("A:A").EntireColumn.Select
Selection.Replace What:="0", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
Selection.Replace What:="1", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
Selection.Replace What:="2", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
ActiveCell.Offset(0, -1).Columns("A:A").EntireColumn.Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=ActiveCell.Offset(-1,0).Range("A:A"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
Now that all the instructions are legal and the code compiles, we can look into tweaking it to make it less redundant and more efficient.
We're dependent on the ActiveCell - that's fine, but we will want to avoid dereferencing the active cell more than once, and we can do that by introducing a variable, using the Dim keyword. Cells are Range objects in the Excel object model, so we declare our variable As Range, and then we assign it using the Set keyword, because it's an object:
Dim cell As Range
Set cell = ActiveCell
Then we can do the same for the active sheet - like this:
Dim sheet As Worksheet
Set sheet = ActiveSheet
Or like this (technically more reliable):
Dim sheet As Worksheet
Set sheet = cell.Parent
The macro is making that cell's FormulaR1C1 a literal string value: that's really more a value than a formula, let alone a formula in R1C1 notation. Setting the cell's Value would make the code more explicit about its intent:
cell.Value = "EmployeeID"
Note that whatever the active cell is is getting this "EmployeeID" value: code should either validate that the cell is in row 1, or specifically write the value in row 1 if that's what it means to do:
ActiveSheet.Cells(1, cell.Column).Value = "EmployeeID"
Next we select the entire column and then work off Selection to find/replace things. We don't need to .Select anything, really:
With cell.EntireColumn
.Replace What:="0", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
.Replace What:="1", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
.Replace What:="2", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
End With
That's redundant, we can eliminate the need for copy-pasting chunks of code by moving that part into a separate Private Sub procedure scope that only does this:
Private Sub ClearValueInColumn(ByVal Column As Range, ByVal Value As String)
Column.Replace What:=Value, _
Replacement:=vbNullString, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
End Sub
Now the With cell.EntireColumn block above, can become this:
ClearValueInColumn(cell.EntireColumn, "0")
ClearValueInColumn(cell.EntireColumn, "1")
ClearValueInColumn(cell.EntireColumn, "2")
The next instruction is problematic:
ActiveCell.Offset(0, -1).Columns("A:A").EntireColumn.Select
If the ActiveCell (or our cell variable) is in row 1, offsetting negative 1 rows is going to blow up, because worksheets don't have a row (or column) 0.
The good news is that the Offset is redundant, because again what we're really looking at is just cell.EntireColumn, and again we don't need to Select anything, but then the next line is also doing redundant dereferencing:
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 ...
The cell variable is referring to a cell on the active sheet, so what we really want here is to get the parent sheet of that cell, rather than to pull a sheet named "Sheet1" (which the user might rename any time - that would instantly break the code!). We've already pulled that object reference into a sheet variable, so let's use it:
sheet.Sort.SortFields.Add2 Key:=cell.EntireColumn, _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
Note that the negative row Offset, as well as the .Range("A:A") member call, are redundant. Avoid any row offsets when you're working with an entire column - especially negative offsets that could attempt to select a cell that's outside the worksheet; always validate that ActiveCell.Row and ActiveCell.Column are large enough to take the subtraction without turning zero or negative.
Lastly, if the macro doesn't really need to work off whatever the active cell is, but is really assuming that the user has selected a specific cell before running the macro, then you can set your cell to the actual cell you need the macro to work with instead of getting the current selection involved - for example this would make the macro work off cell E4:
Set cell = ActiveSheet.Range("E4")
So, that makes the cleaned-up macro look like this:
Public Sub Macro1()
Dim cell As Range
Set cell = ActiveCell
ReplaceValueInColumn(cell.EntireColumn, "0")
ReplaceValueInColumn(cell.EntireColumn, "1")
ReplaceValueInColumn(cell.EntireColumn, "2")
Dim sheet As Worksheet
Set sheet = cell.Parent
sheet.Cells(1, cell.Column).Value = "EmployeeID"
sheet.Sort.SortFields.Clear
sheet.Sort.SortFields.Add2 Key:=cell.EntireColumn, _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
End Sub
Private Sub ReplaceValueInColumn(ByVal Column As Range, ByVal Value As String)
Column.Replace What:=Value, _
Replacement:=vbNullString, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
End Sub
I have a column in excel that has two values "Disqualified" and "Open".
I want to use an If Statement using VBA to change the disqualified values to 0 and the Open values to 1.
Here is the excel formula that shows what I want to do
=IF(H:H="Disqualified","0","1")
I think I need a for loop to loop through all the values in column H but can't seem to get this to work. Thanks
Taking the code in your self-answer, it can (and should) be refactored to get rid of the Select parts (which will almost always generate problems in the future).
Sub changeValues()
With Worksheets("your_sheet_name")
With .Range("H1:H" & .Range("H" & .Rows.Count).End(xlUp).Row)
.Replace What:="Disqualified", _
Replacement:="0", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
.Replace What:="Open", _
Replacement:="1", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
End With
End With
'I doubt if the next line is needed
'ActiveWindow.SmallScroll Down:=-66
End Sub
Well there is probably a better way of writing this but this macro does the job.
Sub changeValues()
'
' changeValues Macro
'
'
Range(Selection, Selection.End(xlDown)).Select
Selection.replace What:="Disqualified", Replacement:="0", LookAt:=xlPart _
, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Selection.replace What:="Open", Replacement:="1", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
ActiveWindow.SmallScroll Down:=-66
End Sub
Right now I am using below macro to replace values in my large data. But the problem is, The replace or replaced values are changing with every data set and if required value not found the macro give error. Can anyone help me, how I use IF condition with Cells.replace. For example IF D found then run this block of code otherwise jump to next value.
Sub ReplaceAll()
Application.ScreenUpdating = False
Sheets("Data").Select
Range("A1").Select
Cells.replace what:="D", Replacement:="", LookAt:=xlPart, SearchOrder:= _
xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
Cells.replace what:="F", Replacement:="", LookAt:=xlPart, SearchOrder:= _
xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
Application.ScreenUpdating = True
End Sub
I don't see why errors should occur, but you could skip all errors.
Sub ReplaceAll()
Application.ScreenUpdating = False
On Error Resume Next 'Skip errors
Sheets("Data").Select
With Range("A1")
.Cells.replace what:="D", Replacement:="", LookAt:=xlPart, SearchOrder:= _
xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
.Cells.replace what:="F", Replacement:="", LookAt:=xlPart, SearchOrder:= _
xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
End With
On Error Goto 0 'Errors will be handled again
Application.ScreenUpdating = True
End Sub
But a better solution would be to handle your errors.
See this link for information about Error handling in VBA
Also, you should try to avoid using Select, because it will slow down your macro an awful lot.
I have some macro like:
Columns("F:M").Select
Selection.Replace What:=",", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=True, SearchFormat:=False, _
ReplaceFormat:=False
But i want to put the current date (or even just a string of text) to be put in cell A of the row where a replace occurred.
I imagine you will need to change your replace to a find and replace. Something like:
Dim c As Range
Columns("F:M").Select
Set c = Selection.Find(What:=",", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=True, SearchFormat:=False)
If Not c Is Nothing Then
Do
c.Replace What:=",", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=True, SearchFormat:=False, _
ReplaceFormat:=False
Cells(c.Row, 1).Value = Date
Set c = Selection.FindNext(c)
Loop While Not c Is Nothing
End If