How do I find the last column with data? - excel

I've found this method for finding the last data containing row in a sheet:
ws.Range("A65536").End(xlUp).row
Is there a similar method for finding the last data containing column in a sheet?

Lots of ways to do this. The most reliable is find.
Dim rLastCell As Range
Set rLastCell = ws.Cells.Find(What:="*", After:=ws.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
MsgBox ("The last used column is: " & rLastCell.Column)
If you want to find the last column used in a particular row you can use:
Dim lColumn As Long
lColumn = ws.Cells(1, Columns.Count).End(xlToLeft).Column
Using used range (less reliable):
Dim lColumn As Long
lColumn = ws.UsedRange.Columns.Count
Using used range wont work if you have no data in column A. See here for another issue with used range:
See Here regarding resetting used range.

I know this is old, but I've tested this in many ways and it hasn't let me down yet, unless someone can tell me otherwise.
Row number
Row = ws.Cells.Find(What:="*", After:=[A1] , SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Column Letter
ColumnLetter = Split(ws.Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Cells.Address(1, 0), "$")(0)
Column Number
ColumnNumber = ws.Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column

Try using the code after you active the sheet:
Dim J as integer
J = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
If you use Cells.SpecialCells(xlCellTypeLastCell).Row only, the problem will be that the xlCellTypeLastCell information will not be updated unless one do a "Save file" action. But use UsedRange will always update the information in realtime.

I think we can modify the UsedRange code from #Readify's answer above to get the last used column even if the starting columns are blank or not.
So this lColumn = ws.UsedRange.Columns.Count modified to
this lColumn = ws.UsedRange.Column + ws.UsedRange.Columns.Count - 1 will give reliable results always
?Sheet1.UsedRange.Column + Sheet1.UsedRange.Columns.Count - 1
Above line Yields 9 in the immediate window.

Here's something which might be useful. Selecting the entire column based on a row containing data, in this case i am using 5th row:
Dim lColumn As Long
lColumn = ActiveSheet.Cells(5, Columns.Count).End(xlToLeft).Column
MsgBox ("The last used column is: " & lColumn)

I have been using #Reafidy method/answer for a long time, but today I ran into an issue with the top row being merged cell from A1-->N1 and my function returning the "Last Column" as 1 not 14.
Here is my modified function now account for possibly merged cells:
Public Function Get_lRow(WS As Worksheet) As Integer
On Error Resume Next
If Not IsWorksheetEmpty(WS) Then
Get_lRow = WS.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Dim Cell As Range
For Each Cell In WS.UsedRange
If Cell.MergeCells Then
With Cell.MergeArea
If .Cells(.Cells.Count).Row > Get_lRow Then Get_lRow = .Cells(.Cells.Count).Row
End With
End If
Next Cell
Else
Get_lRow = 1
End If
End Function
Public Function Get_lCol(WS As Worksheet) As Integer
On Error Resume Next
If Not IsWorksheetEmpty(WS) Then
Get_lCol = WS.Cells.Find(What:="*", after:=[A1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
Dim Cell As Range
For Each Cell In WS.UsedRange
If Cell.MergeCells Then
With Cell.MergeArea
If .Cells(.Cells.Count).Column > Get_lCol Then Get_lCol = .Cells(.Cells.Count).Column
End With
End If
Next Cell
Else
Get_lCol = 1
End If
End Function

Here's a simple option if your data starts in the first row.
MsgBox "Last Row: " + CStr(Application.WorksheetFunction.CountA(ActiveSheet.Cells(1).EntireRow))
It just uses CountA to count the number of columns with data in the entire row.
This has all sorts of scenarios where it won't work, such as if you have multiple tables sharing the top row, but for a few quick & easy things it works perfect.

Related

Merge 2 columns and find text VBA

I have one table and one file. I can find the text which is in specific place in file inside the table.
However, the texts are not unique all the time, so I decided to combine 2 cells in file and try to find in table. unless, I cannot find a way to combine 2 columns in table to match it with combined 2 cells in file.
Below you may see example table.
my aim is adding date in cell next cell of Units. So I try to find A1234 instead of 1234 due to 1234 not unique.
FindString = wb.Sheets("1").Range("E4").Value & wb.Sheets("1").Range("E5").Value
If Trim(FindString) <> "" Then
With Wb2.Sheets("Sheet1").Range("A:A") 'this section need to be amended and need combine column A&B
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
Rng.Offset(0, 1).Value = wb.Sheets("1").Range("I4") ' if column A&B combining completed then next cell probably will not work
Else
MsgBox "Nothing found in the list"
End If
This is similar to the variant strategy mentioned in the comments-- Try looping through your data with a For loop and an If Statement looking for both values to match. Here's an example code that shows the concept
Sub test()
Dim s As Worksheet, findstring1 As String, findstring2 As String
Dim firstrow As Integer, lastrow As Integer, i As Integer
Set s = Sheets("test")
findstring1 = "A "'replace this with the Customer reference (what to search for)
findstring2 = "1234" 'replace this with the unit reference
firstrow = 2 ' row number for first cell with data
lastcell = s.Cells(2, 1).End(xlDown).Row 'find last cell row number (end of data)
For i = firstrow To lastcell
If s.Cells(i, 1) = findstring1 And s.Cells(i, 2) = findstring2 Then
'do something with found values
End If
Next i
End Sub

VBA, find last used column in the whole sheet

I googled a lot and found a lot of different solutions, but I need to improve the one I'm using now.
I want to find the last used column in the sheet using the find method not to consider the deleted cells.
All I want is to get the last column used, including the one in the row of the starting cell. In the image below if I use my code it will give last column = 4, because in the 2nd row data stops at column 4. Why isn't it giving 5 (header column) as result?
Thank you!!
With ActiveSheet
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
findlastcol = .Cells.Find(What:="*", _
After:=.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
Else
findlastcol = 1
End If
End With
Example Table screenshot
+---------+---------+---------+---------+---------+
| Header1 | Header2 | Header3 | Header4 | Header5 |
+---------+---------+---------+---------+---------+
| Data | Data | Data | Data | |
+---------+---------+---------+---------+---------+
AutoFilter Kicks the Find Method
The Find method with xlFormulas is pretty much 'bullet proof', unless there is a filter involved which is happening in your case.
The following example shows how to do it by turning the AutoFilter off, which is not quite what one wants. It also shows how there were three not needed arguments. Additionally it is a different approach which does not need CountA.
A proper solution would be to copy the current filter into a Filter object and then apply it later back. Here is an example of how to do it.
The Code
Sub testBulletProof()
Dim LastCol As Long
Dim rng As Range
With ActiveSheet
If .AutoFilterMode Then
.AutoFilterMode = False
End If
Set rng = .Cells.Find(What:="*", _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious)
End With
If Not rng Is Nothing Then
LastCol = rng.Column
Else
LastCol = 1
End If
Debug.Print LastCol
End Sub
Since you might know the row where the headers are and the data will not have more columns then the header does, you could use this:
The Code
Sub testFindInRow()
Dim LastCol As Long
Dim rng As Range
With ActiveSheet
Set rng = .Rows(1).Find(What:="*", _
LookIn:=xlFormulas, _
SearchDirection:=xlPrevious)
End With
If Not rng Is Nothing Then
LastCol = rng.Column
Else
LastCol = 1
End If
Debug.Print LastCol
End Sub
You could try the following code:
Sub FindLastColumn()
Dim iLastCol As Integer
ActiveSheet.UsedRange 'Refreshing used range (may need to save wb also)
iLastCol = ActiveSheet.UsedRange.Columns(ActiveSheet.UsedRange.Columns.Count).Column
End Sub
Alternatively, you can try:
findlastcol = Selection.SpecialCells(xlCellTypeLastCell).Column

ActiveSheet.UsedRange.Rows.count giving wrong and different result on each run [duplicate]

This question already has answers here:
Find last used cell in Excel VBA
(14 answers)
Closed 5 years ago.
My Worksheet has 29 rows and 39 columns.
Currently I use
lrow = ActiveSheet.UsedRange.Rows.count --> for getting used rows count
lColumn = ActiveSheet.UsedRange.Columns.count --> for getting used columns count
Excel gives wrong count every time it runs. Sometimes it gives:
Rows: 29 Columns: 784
On other runs it gives
Rows: 32755 and Columns as: 784
and on other runs it gives different values.
I have checked there is no junk data after 29 rows and after 39 columns. Also,
Previous to filling the data I clear the sheet with: ActiveWorkbook.Worksheets("Field Difference").Cells.Delete
I hope ActiveWorkbook.Worksheets("Field Difference").Cells.Delete completely clears the sheet and clears the sheet of the junk data if any on the sheet. How else I can make sure that there is no junk data in the worksheet.
I do understand that we have other Options such as:
ActiveWorkbook.Worksheets("Field Difference").UsedRange.ClearContents - to clear only contents
ActiveWorkbook.Worksheets("Field Difference").UsedRange.Clear - to clear formatting as well.
Please do let me know why I am getting wrong values for the count of rows and columns and what is the way out. Can I use any other reliable way to get the UsedRange row count and UsedRange columns count.
For Last Row and Column in Column A:
Dim sht as Worksheets
dim lRow as Long
Set sht = Worksheets("Field Difference")
lRow = sht.Cells(sht.Rows.Count, 1).End(xlUp).Row
lCol = sht.Cells(1, sht.Columns.Count).End(xlToLeft).Column
Worksheet layout can affect the .UsedRange and .CurrentRegion properties. For a definitive 'last cell' search backwards from A1 first by rows then by columns using a blanket wildcard.
dim lr as long, lc as long
with worksheets("sheet1")
lr = .cells.find(what:=chr(42), after:=.cells(1), searchdirection:=xlprevious, _
lookat:=xlpart, searchorder:=xlbyrows, lookin:=xlformulas).row
lc = .cells.find(what:=chr(42), after:=.cells(1), searchdirection:=xlprevious, _
lookat:=xlpart, searchorder:=xlbycolumns, lookin:=xlformulas).column
debug.print .cells(lr, lc).address(0, 0)
end with
Methods for finding the last populated cell for a given column(row) are well know. using End(xlUp) (End(xlToLeft)) from the last cell of that column (row).
To get the last cell of the actually populated region of a worksheet, you can use this custom function which will get it to you reliably:
Public Function getLastCell(sh As Worksheet) As Range
Dim lastRow As Long, lastCol As Long
lastRow = sh.Cells.Find("*", sh.Cells(1, 1), xlFormulas, xlPart, xlByRows, xlPrevious).Row
lastCol = sh.Cells.Find("*", sh.Cells(1, 1), xlFormulas, xlPart, xlByColumns, xlPrevious).Column
Set getLastCell = sh.Cells(lastRow, lastCol)
End Function
By bringing the last cell, you can get the whole range from A1 to that cell, using
mysheet.Range("A1", getLastCell(mySheet))
Occasionally you might be interested in finding the populated region which is not starting at A1. You can, in this case, find Similarly the "Topleft" Cell of the actually populated region, using this custom function:
Public Function getFirstCell(sh As Worksheet) As Range
Dim lastRow As Long, lastCol As Long
lastRow = sh.Cells.Find("*", sh.Cells(sh.Rows.Count, sh.Columns.Count), xlFormulas, xlPart, xlByRows, xlNext).Row
lastCol = sh.Cells.Find("*", sh.Cells(sh.Rows.Count, sh.Columns.Count), xlFormulas, xlPart, xlByColumns, xlNext).Column
Set getFirstCell = sh.Cells(lastRow, lastCol)
End Function
finally, you can join the two cells to get the actually ppulated region, like this:
mysheet.Range(getFirstCell(mySheet), getLastCell(mySheet))

Countering circular reference with SUM and OFFSET (VLOOKUP & VBA involved)

To give you a breakdown of my spreadsheet:
I have a master spreadsheet that pulls data from another spreadsheet (generated daily), placing it into the next empty column and converting the column that previously held the formula to values. This is achieved with a combination of the following formula and VBA code:
=IF(ISNA(VLOOKUP("Row 1",'N:\Reports\[data.xls]Sheet1'!$A$2:$B$40,2,FALSE)),0,(VLOOKUP("Row 1",'N:\Reports\[data.xls]Sheet1'!$A$2:$B$40,2,FALSE)))
Sub Test()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim rLastCell As Range
Dim LastCol As Integer
Set rLastCell = ws.Cells.Find(what:="*", After:=ws.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
LastCol = rLastCell.Column
ws.Columns(LastCol).Copy ws.Columns(LastCol + 1)
With ws.Columns(LastCol)
.Copy .Offset(0, 1)
.Value = .Value
End With
End Sub
The intention is for Column B to be a 'totals' column, that dynamically sums all of the values in the relevant row as new entries are pulled by the formula/VBA combo and added to the first blank column. Unfortunately though, I also need to subtract that row's total from the value that the formula returns--however, doing so creates a circular reference.
My solution was to just exclude the last cell in the row (that has the formula) from the total, with this:
=SUM(C2:OFFSET(I$2,0,-1))
However, the dynamic range doesn't appear all that dynamic. It doesn't expand to include the next column when a new record is added, and I'm really not enough of a hand at this stuff to figure out why or how to rectify it.
Thanks in advance for any assistance with this and please don't hesitate to ask for any clarification!
It may be simplest to use a named range. If you name the column before the monthly total say LastDay, you can use:
=SUM(C2:INDEX(LastDay,ROW())
as your formula, and your code then becomes:
Sub Test()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim rLastCell As Range
Dim LastCol As Integer
Set rLastCell = ws.Cells.Find(what:="*", After:=ws.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
LastCol = rLastCell.Column
With ws.Columns(LastCol)
.Copy .Offset(0, 1)
.Value = .Value
.Name = "LastDay"
End With
End Sub
Assuming I have understood your layout correctly.

Getting the actual usedrange

I have a Excel worksheet that has a button.
When I call the usedRange() function, the range it returns includes the button part.
Is there anyway I can just get actual used range that contains data?
What sort of button, neither a Forms Control nor an ActiveX control should affect the used range.
It is a known problem that excel does not keep track of the used range very well. Any reference to the used range via VBA will reset the value to the current used range. So try running this sub procedure:
Sub ResetUsedRng()
Application.ActiveSheet.UsedRange
End Sub
Failing that you may well have some formatting hanging round. Try clearing/deleting all the cells after your last row.
Regarding the above also see:
Excel Developer Tip
Another method to find the last used cell:
Dim rLastCell As Range
Set rLastCell = ActiveSheet.Cells.Find(What:="*", After:=.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
Change the search direction to find the first used cell.
Readify made a very complete answer. Yet, I wanted to add the End statement, you can use:
Find the last used cell, before a blank in a Column:
Sub LastCellBeforeBlankInColumn()
Range("A1").End(xldown).Select
End Sub
Find the very last used cell in a Column:
Sub LastCellInColumn()
Range("A" & Rows.Count).End(xlup).Select
End Sub
Find the last cell, before a blank in a Row:
Sub LastCellBeforeBlankInRow()
Range("A1").End(xlToRight).Select
End Sub
Find the very last used cell in a Row:
Sub LastCellInRow()
Range("IV1").End(xlToLeft).Select
End Sub
See here for more information (and the explanation why xlCellTypeLastCell is not very reliable).
Here's a pair of functions to return the last row and col of a worksheet, based on Reafidy's solution above.
Function LastRow(ws As Object) As Long
Dim rLastCell As Object
On Error GoTo ErrHan
Set rLastCell = ws.Cells.Find("*", ws.Cells(1, 1), , , xlByRows, _
xlPrevious)
LastRow = rLastCell.Row
ErrExit:
Exit Function
ErrHan:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbExclamation, "LastRow()"
Resume ErrExit
End Function
Function LastCol(ws As Object) As Long
Dim rLastCell As Object
On Error GoTo ErrHan
Set rLastCell = ws.Cells.Find("*", ws.Cells(1, 1), , , xlByColumns, _
xlPrevious)
LastCol = rLastCell.Column
ErrExit:
Exit Function
ErrHan:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbExclamation, "LastRow()"
Resume ErrExit
End Function
Public Sub FindTrueUsedRange(RowLast As Long, ColLast As Long)
Application.EnableEvents = False
Application.ScreenUpdating = False
RowLast = 0
ColLast = 0
ActiveSheet.UsedRange.Select
Cells(1, 1).Activate
Selection.End(xlDown).Select
Selection.End(xlDown).Select
On Error GoTo -1: On Error GoTo Quit
Cells.Find(What:="*", LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Activate
On Error GoTo -1: On Error GoTo 0
RowLast = Selection.Row
Cells(1, 1).Activate
Selection.End(xlToRight).Select
Selection.End(xlToRight).Select
Cells.Find(What:="*", LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Activate
ColLast = Selection.Column
Quit:
Application.ScreenUpdating = True
Application.EnableEvents = True
On Error GoTo -1: On Error GoTo 0
End Sub
This function returns the actual used range to the lower right limit. It returns "Nothing" if the sheet is empty.
'2020-01-26
Function fUsedRange() As Range
Dim lngLastRow As Long
Dim lngLastCol As Long
Dim rngLastCell As Range
On Error Resume Next
Set rngLastCell = ActiveSheet.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious)
If rngLastCell Is Nothing Then 'look for data backwards in rows
Set fUsedRange = Nothing
Exit Function
Else
lngLastRow = rngLastCell.Row
End If
Set rngLastCell = ActiveSheet.Cells.Find("*", searchorder:=xlByColumns, searchdirection:=xlPrevious)
If rngLastCell Is Nothing Then 'look for data backwards in columns
Set fUsedRange = Nothing
Exit Function
Else
lngLastCol = rngLastCell.Column
End If
Set fUsedRange = ActiveSheet.Range(Cells(1, 1), Cells(lngLastRow, lngLastCol)) 'set up range
End Function
I use the following vba code to determine the entire used rows range for the worksheet to then shorten the selected range of a column:
Set rUsedRowRange = Selection.Worksheet.UsedRange.Columns( _
Selection.Column - Selection.Worksheet.UsedRange.Column + 1)
Also works the other way around:
Set rUsedColumnRange = Selection.Worksheet.UsedRange.Rows( _
Selection.Row - Selection.Worksheet.UsedRange.Row + 1)
This function gives all 4 limits of the used range:
Function FindUsedRangeLimits()
Set Sheet = ActiveSheet
Sheet.UsedRange.Select
' Display the range's rows and columns.
row_min = Sheet.UsedRange.Row
row_max = row_min + Sheet.UsedRange.Rows.Count - 1
col_min = Sheet.UsedRange.Column
col_max = col_min + Sheet.UsedRange.Columns.Count - 1
MsgBox "Rows " & row_min & " - " & row_max & vbCrLf & _
"Columns: " & col_min & " - " & col_max
LastCellBeforeBlankInColumn = True
End Function
Timings on Excel 2013 fairly slow machine with a big bad used range million rows:
26ms Cells.Find xlPrevious method (as above)
0.4ms Sheet.UsedRange (just call it)
0.14ms Counta binary search + 0.4ms Used Range to start search (12 CountA calls)
So the Find xlPrevious is quite slow if that is of concern.
The CountA binary search approach is to first do a Used Range. Then chop the range in half and see if there are any non-empty cells in the bottom half, and then halve again as needed. It is tricky to get right.
Here's another one. It looks for the first and last non empty cell and builds are range from those. This also handles cases where your data is not rectangular and does not start in A1. Furthermore it handles merged cells as well, which .Find skips when executed from a macro, used on .Cells on a worksheet.
Function getUsedRange(ByRef sheet As Worksheet) As Range
' finds used range by looking for non empty cells
' works around bug in .Find that skips merged cells
' by starting at with the UsedRange (that may be too big)
' credit to https://contexturesblog.com/archives/2012/03/01/select-actual-used-range-in-excel-sheet/
' for the .Find commands
Dim excelsUsedRange As Range
Dim lastRow As Long
Dim lastCol As Long
Dim lastCell As Range
Dim firstRow As Long
Dim firstCol As Long
Dim firstCell As Range
Set excelsUsedRange = ActiveSheet.UsedRange
lastRow = excelsUsedRange.Find(What:="*", _
LookIn:=xlValues, SearchOrder:=xlRows, _
SearchDirection:=xlPrevious).Row
lastCol = excelsUsedRange.Find(What:="*", _
LookIn:=xlValues, SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
Set lastCell = sheet.Cells(lastRow, lastCol)
firstRow = excelsUsedRange.Find(What:="*", After:=lastCell, _
LookIn:=xlValues, SearchOrder:=xlRows, _
SearchDirection:=xlNext).Row
firstCol = excelsUsedRange.Find(What:="*", After:=lastCell, _
LookIn:=xlValues, SearchOrder:=xlByColumns, _
SearchDirection:=xlNext).Row
Set firstCell = sheet.Cells(firstRow, firstCol)
Set getUsedRange = sheet.Range(firstCell, lastCell)
End Function
This is a different approach to the other answers, which will give you all the regions with data - a Region is something enclosed by an empty row and column and or the the edge of the worksheet. Basically it gives all the rectangles of data:
Public Function ContentRange(ByVal ws As Worksheet) As Range
'First, identify any cells with data, whose neighbourhood we will inspect
' to identify contiguous regions of content
'For efficiency, restrict our search to only the UsedRange
' NB. This may be pointless if .SpecialCells does this internally already, it probably does...
With ws.UsedRange 'includes data and cells that have been formatted
Dim cellsWithContent As Range
On Error Resume Next '.specialCells will error if nothing found, we can ignore it though
Set cellsWithContent = .SpecialCells(xlCellTypeConstants)
Set cellsWithContent = Union(cellsWithContent, .SpecialCells(xlCellTypeFormulas))
On Error GoTo 0
End With
'Early exit; return Nothing if there is no Data
If cellsWithContent Is Nothing Then Exit Function
'Next, loop over all the content cells and group their currentRegions
' This allows us to include some blank cells which are interspersed amongst the data
' It is faster to loop over areas rather than cell by cell since we merge all the CurrentRegions either way
Dim item As Range
Dim usedRegions As Range
For Each item In cellsWithContent.Areas
'Debug.Print "adding: "; item.Address, item.CurrentRegion.Address
If usedRegions Is Nothing Then
Set usedRegions = item.CurrentRegion 'expands "item" to include any surrounding non-blank data
Else
Set usedRegions = Union(usedRegions, item.CurrentRegion)
End If
Next item
'Debug.Print cellsWithContent.Address; "->"; usedRegions.Address
Set ContentRange = usedRegions
End Function
Used like:
Debug.Print ContentRange(Sheet1).Address '$A$1:$F$22
Debug.Print ContentRange(Sheet2).Address '$A$1:$F$22,$N$5:$M$7
The result is a Range object containing 1 or more Areas, each of it which will represent a data/formula containing region on the sheet.
It is the same technique as clicking in all the cells in your sheet and pressing Ctrl+T, merging all those areas. I'm using it to find potential tables of data

Resources