In Column L (only) I want to replace any instance of data with "True" regardless of what was originally in any of the Column L cells. The code I tried was:
With ActiveSheet
intLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Let strSelectRange = "L2" & ":" & "L" & intLastRow
Range(strSelectRange).Select
Cells.Replace What:="*", Replacement:="True", LookAt:=xlPart _
, SearchOrder:=xlByColumns, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
End With
First, I used .Rows.Count, "A" because in that column every row has data so I know how many rows to go down in Column L. In Column L many cells will be blank.
When I run this, every cell in the entire worksheet that has anything in it, is changed to True, not just the data in Column L.
Another method I tried was:
Range("L2:L1200").Select
Selection.Replace What:="*", Replacement:="True", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Range("A1").Select
What I don't like about this is that I picked L1200 as the number of rows just to be sure I'd search farther than the actual last row that can contain data. I'm worried that this method might cause some kind of problem at some point.
What I'd really like to know is what I'm doing wrong in the first code example.
Thanks for any help you can offer!!!
Search & Replace in Column
Use Option Explicit always, to quicker learn about the occurring
errors and to be forced to declare variables.
You should always declare your rows as Long.
When you use the With statement you use the dots on everything, even
on .Range and .Cells etc. The code might work in this case
(ActiveSheet) anyway, but it is incorrect.
Avoid the use of ActiveSheet, use the worksheet name.
Avoid the use of Select. There are many posts (articles) about this.
When ever you use Cells without anything behind it, it refers to all the
cells in the worksheet.
The first thing in the Replace function (Find function) is the range
where you're going to Replace (Find, Search). It can be a column, it
can be Cells or just a smaller range.
The Code
Sub SROneColumn()
Const cVntLRColumn As Variant = "A" ' Last Row Column Letter/Number
Const cVntCriteria As Variant = "L" ' Criteria Column Letter/Number
Const cLngFirstRow As Long = 2 ' First Row Number
Const cStrReplace As String = "True" ' Replace String
Dim lngLastRow As Long ' Last Row Number
Dim strSelectRange As String ' Select Range Address
With ActiveSheet
lngLastRow = .Cells(.Rows.Count, cVntLRColumn).End(xlUp).Row
strSelectRange = .Range(.Cells(cLngFirstRow, cVntCriteria), _
.Cells(lngLastRow, cVntCriteria)).Address
.Range(strSelectRange).Replace What:="*", Replacement:=cStrReplace, _
LookAt:=xlPart, SearchOrder:=xlByColumns, MatchCase:=False
End With
End Sub
An interesting way to use a worksheet without the use of an object variable:
Sub SRSheet()
Const cStrSheet As Variant = "Sheet1" ' Worksheet Name/Index
With ThisWorkbook.Worksheets(cStrSheet)
End With
End Sub
Range(strSelectRange).Select
selects a range (though best to avoid Select) but then your code does nothing with that selection because Cells is the entire sheet.
Maybe you want instead:
Range(strSelectRange).Replace What:="*", Replacement:="True", LookAt:=xlPart
Related
I have a workbook that tracks long-term trends in experimental data. Independant workbooks for various experiments generate 2-3 columns of data that need to be copied to this tracking workbook. I would probably go for something like this:
Workbooks(source_book).Worksheets(source_sheet).Range(Source_Range_Variable).Copy
Workbooks(target_book).Worksheets(target_sheet).Range(Target_Range_Variable).PasteSpecial xlPasteValues
My issue is that I have no idea how to find "Target_Range_Variable" which would be the first empty column in the target sheet. I have some ideas on how to set "Source_Range_Variable" because it can be one or two columns by using nested if's to find if columns are populated and going from there. Inelegant for sure.
Sorry I don't have any real code, but I truly don't know how to start. There are several hundred columns already, and there will be several hundred more. If it wasn't so big, I would brute force my way by nesting if statements until it finds an empty column.
Note: I'm very inexperienced with this, forgive me if I miss anything obvious.
You can use Cells.Find method to find the last column. Here is an example (Untested)
Sub Sample()
'
'~~> Rest of code
'
Workbooks(source_book).Worksheets(source_sheet).Range(Source_Range_Variable).Copy
Dim LastCol As Long
Dim ColName As String
'~~> Get the last column number
LastCol = LastColumn(Workbooks(target_book).Worksheets(target_sheet))
'~~> Column number to column letter
ColName = Split(Cells(, LastCol).Address, "$")(1)
'~~> Your final range. Ex "A1"
Target_Range_Variable = ColName & 1
Workbooks(target_book).Worksheets(target_sheet).Range(Target_Range_Variable).PasteSpecial xlPasteValues
End Sub
Private Function LastColumn(wks As Worksheet) As Long
If Application.WorksheetFunction.CountA(wks.Cells) <> 0 Then
LastColumn = wks.Cells.Find(What:="*", _
After:=wks.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
Else
LastColumn = 1
End If
End Function
I am trying to check whether Row 1 of my active sheet named "Exceptions" contains the text "Control Date" (two spaces) or "Control Date".
My code finds the condition false.
Dim a As Range
Dim exceptions As Worksheet
Set exceptions = ActiveWorkbook.Worksheets("Exceptions")
For Each c In Exceptions.Range("A1:Z1")
If c = "Control Date" Then
Cells.Find(What:="control date", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
Else
Cells.Find(What:="Control Date", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
End If
Next c
Example of a worksheet with two spaces in "Control Date"
How to write the condition
As far as checking if the cell value is "Control Date" with a single space or one with two spaces, there are two ways of going about it:
Use the like operator
The like operator makes it easy to compare a string to a basic pattern. In this example, using the wildcard character * (Zero or more characters) will return true regardless of how many spaces are between Control and Date.
If cell.Value2 Like "Control*Date" Then
' Do something with that cell
End If
Use the or operator
Using the or operator ok to use as well, although not a flexible and perhaps a bit more difficult to see what's going on for your specific example.
If cell.Value2 = "Control Date" Or cell.Value2 = "Control Date" Then
' Do something with that cell
End If
Worksheet Codename
Each worksheet has whats called a codename. This is a reference that can be called directly in the code to that specific worksheet by it's name.
To set this name, in the properties window update the name property
So instead of
Dim Exceptions As Worksheet
Set Exceptions = ActiveWorkbook.Worksheets("Exceptions")
For Each cell In Exceptions.Range("A1:Z1")
' Do something...
Next cell
you can call the worksheet reference directly
For Each cell In Exceptions.Range("A1:Z1")
' Do something...
Next cell
Putting it together
Instead of using c for your variable, I like to make my variables easier to read and follow so I used cell.
Also, instead of hard coding your header columns in range, you could loop the cells of the entire first row. This is option suggestion though.
Lastly, be more explicit in what property you are looking for in your Cell. In my example I use .value2 to show I am looking for the value of that cell.
Public Sub Demo()
Dim cell As Range
For Each cell In Exceptions.Rows(1).Cells
If cell.Value2 Like "Control*Date" Then
' Do something with that cell
End If
Next cell
End Sub
Why duplicate the data into a third column? Whenever you need the "combined" date, just go get it, but do not store it twice.
Option Explicit '<<-- always have this
Sub doFindControl()
Dim a As Range
Dim c As Range '<<-- add this
Dim colDate As Long, colNumber As Long, colBlank As Long '<<--add this
Dim exceptions As Worksheet
Set exceptions = ActiveWorkbook.Worksheets("Exceptions")
For Each c In exceptions.Range("A1:Z1")
' first find the 2 key columns
If InStr(c, "Control") > 0 Then
If InStr(c, "Date") > 0 Then
colDate = c.Column
ElseIf InStr(c, "Number") > 0 Then
colNumber = c.Column
End If
' second look for the first blank column for you to put results in
ElseIf c.Text = "" Then
colBlank = c.Column
Exit For ' stop looking after its found
End If
Next c
' now you have the 2 FROM columns, and the TO column
MsgBox (colDate & " " & colNumber & " " & colBlank)
' and you can loop thru all the rest of the rows doing combine
End Sub
Thank you for all the answers! Robert Todar's answer led me to my lightbulb moment, and I can't believe at how simple the answer was. All I had to do was change this code:
Cells.Find(What:="Control Date", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
to:
Cells.Find(What:="Control*Date", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
I have a table in Sheet1. I need to search in Sheet1 for terms in Sheet2-ColumnA.
The exclusion list in Sheet2-ColumnA does not match the cell contents in Sheet1, but is found within the cell contents (Ex: find "orange" in "yellow;orange" or "orange;yellow").
If that criteria is found, delete the row. If it doesn't find the criteria, continue on down the list until it reaches an empty cell.
I recorded one round of this, but I need to modify it to loop through the entire exclusion list until it reaches an empty cell in the exclusion list.
Sub ExclusionList()
'
' ExclusionList Macro
' Find terms from exclusion list and delete row
'
' Go to sheet2 and select first term in exclusion list
Sheets("Sheet2").Select
Range("A1").Select
' Copy cell contents and find in sheet 1
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
Cells.Find(What:="orange", After:=ActiveCell, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
' Delete row if found
Application.CutCopyMode = False
Selection.EntireRow.Delete
End Sub
In this example, "orange" is the criteria in Sheet2 A1. If it is possible to skip the copy/paste and refer directly to the exclusion list in the Cells.Find() function it seems like that would clean up the code and be more efficient overall.
Try this.
Here is a useful resource on avoiding Select/Activate. This shortens code considerably and makes it more effective.
Sub ExclusionList()
Dim r As Range, rFind As Range
With Sheets("Sheet2")
For Each r In .Range("A1", .Range("A" & Rows.Count).End(xlUp)) 'loop through every cell in sheet2 column A
Set rFind = Sheets("Sheet1").Cells.Find(What:=r.Value, LookAt:=xlPart, MatchCase:=False, SearchFormat:=False)
If Not rFind Is Nothing Then 'check that value is found to avoid error on next line
rFind.EntireRow.Delete
End If
Next r
End With
End Sub
I am fairly new to excel and I am trying to setup a macro that adds a row after a specific point of the worksheet. Example: Row 2 contains text "Original", so it should insert a new row afterwards, and so on.
I know that it might be easier to insert before something, so I could change the setup (so for example the word "original" would be in row 2 and the new row is added above it) if that is an easier solution.
Is this possible? How?
Thanks for all the possible help.
Slightly simpler than the previous answer:
Sub NewRowInsert()
Dim SearchText As String
Dim GCell As Range
SearchText = "Original"
Set GCell = Cells.Find(SearchText).Offset(1)
GCell.EntireRow.Insert
End Sub
This will work with the current active sheet. If you want to use some other sheet, say Sheet2, you could use:
Set GCell = Worksheets("Sheet2").Cells.Find(SearchText).Offset(1)
and if you wanted to operate on a different workbook e.g. TestBook.xlsx, you could use:
Set GCell = Workbooks("TestBook.xlsx").Worksheets("Sheet2").Cells.Find(SearchText).Offset(1)
Note that I've avoided the use of select. This may not be an issue for you, but if you're searching through thousands of rows and making many replacements it could speed up your code considerably.
Try the code below = you can change the textvalue variable value to what ever you want to search for.
Sub newRow()
Dim textvalue As String
textvalue = "Original"
Cells.Find(What:=textvalue, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
ActiveCell.offset(rowOffset:=1, columnOffset:=0).Activate
ActiveCell.EntireRow.Insert
End Sub
I've got part of a solution but it isn't working like I'd hope, so I've come to you for advice.
I regularly receive Excel files where I need to amend formatting. I'm trying to learn VBA by automating as much of these procedures as possible.
One particular format I complete is converting the date to "DDMMYYYY" (09091986), where it usually comes in as 09/09/1986.
Within my worksheet, there are a total of 3 columns containing dates, all of which need the same formatting and all of which have the word "DATE" in the heading. They are not adjacent to each other.
I must also be careful not to have any other data affected, as I have names and addresses which may contain the characters "DATE".
So, background out of the way... I'm trying to search the first row until I find the word "Date" and then format that for each cell until the last row, before moving on to the next column containing the word "DATE" and repeating this until all columns with the word "DATE" have been formatted.
I'm sure you have a simple solution but I can't seem to find it myself.
Here is the code I have...
Sub Dateformat()
Dim LastRow As Integer
Dim FindCol As Integer
Dim C1 As Integer
LastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
FindCol = Cells.Find(What:="DATE", LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Column
For C1 = 2 To LastRow
Cells(C1, FindCol).NumberFormat = "DDMMYYYY"
Next C1
End Sub
This works for the first column containing date but doesn't move on to the next column.
Thanks for the help
Regards,
Adam
As you know, you need to loop through and find each Row Header with DATE
Here is one way to do it.
Sub Dateformat()
Dim wks As Worksheet
Dim LastRow As Integer
Dim FindCol As Range
Dim sAdd As String
Set wks = ThisWorkbook.Sheets("Sheet1") ' adjust as needed
With wks
LastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'find first instance where DATE exists in row 1 (headers)
Set FindCol = .Rows(1).Find(What:="DATE", LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
'store address of first found instance (to check in loop)
sAdd = FindCol.Address
Do
'format column (row 2 to last used row)
.Range(.Cells(2, FindCol.Column), .Cells(LastRow, FindCol.Column)).NumberFormat = "DDMMYYYY"
'this line works as well and is a bit cleaner
'.Cells(2, FindCol.Column).Resize(LastRow - 1, 1).NumberFormat = "DDMMYYYY"
'find next instance (begin search after current instance found)
Set FindCol = .Cells.FindNext(After:=FindCol)
'keep going until nothing is found or the loop finds the first address again (in which case the code can stop)
Loop Until FindCol Is Nothing Or FindCol.Address = sAdd
End With
End Sub