获取实际使用范围
Posted
技术标签:
【中文标题】获取实际使用范围【英文标题】:Getting the actual usedrange 【发布时间】:2011-09-14 21:09:29 【问题描述】:我有一个带有按钮的 Excel 工作表。
当我调用 usedRange() 函数时,它返回的范围包括按钮部分。
反正我可以得到包含数据的实际使用范围吗?
【问题讨论】:
【参考方案1】:什么样的按钮,窗体控件和 ActiveX 控件都不应该影响使用的范围。
excel 不能很好地跟踪使用的范围是一个已知问题。通过 VBA 对使用范围的任何引用都会将该值重置为当前使用的范围。所以尝试运行这个子过程:
Sub ResetUsedRng()
Application.ActiveSheet.UsedRange
End Sub
如果你可能有一些格式悬而未决。尝试清除/删除最后一行之后的所有单元格。
关于以上内容另见:
Excel Developer Tip
另一种查找最后使用的单元格的方法:
Dim rLastCell As Range
Set rLastCell = ActiveSheet.Cells.Find(What:="*", After:=.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
更改搜索方向以查找第一个使用的单元格。
【讨论】:
我会试试这个。我最终编写了自己的搜索功能。基本上,如果我找到一个空单元格,我会计算下一个 100 行。如果总数为 0,我认为它是最后一行。 在调用Find
之前,请确保您有ActiveSheet.AutoFilterMode=False
,否则将不会考虑某些具有实际内容的行。
没有。 Sheet.UsedRange 不能可靠地重置它。它有时会出错并一直出错。 Excel 2007 似乎确实有所改善。
...但仍然可能出错,特别是如果有数据透视表。
至少在 Excel 2016 中,.Find 命令在用于 .Cells 范围时会跳过合并的单元格,不幸的是,当它们位于已用范围的边界时。【参考方案2】:
Readify 给出了非常完整的答案。但是,我想添加End
语句,您可以使用:
在列中的空白之前查找最后使用的单元格:
Sub LastCellBeforeBlankInColumn()
Range("A1").End(xldown).Select
End Sub
在列中查找最后使用的单元格:
Sub LastCellInColumn()
Range("A" & Rows.Count).End(xlup).Select
End Sub
查找行中空白之前的最后一个单元格:
Sub LastCellBeforeBlankInRow()
Range("A1").End(xlToRight).Select
End Sub
查找一行中最后使用的单元格:
Sub LastCellInRow()
Range("IV1").End(xlToLeft).Select
End Sub
请参阅here 了解更多信息(以及为什么xlCellTypeLastCell
不太可靠的解释)。
【讨论】:
+1 很棒的信息。我建议使用 Range("A" & Rows.Count).End(xlup) 这样您的代码对于多个版本的 excel 都是可行的。【参考方案3】:根据上述 Reafidy 的解决方案,这是一对返回工作表的最后一行和最后一行的函数。
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
【讨论】:
非常好。我使用了二进制搜索,但这更简单,应该更快。但是,您可能还想指定 Lookin:=xlFormulas;公式可能会返回 "" 其实不是,""匹配"*",和isempty()不同。【参考方案4】: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
【讨论】:
【参考方案5】:此函数将实际使用的范围返回到右下限。如果工作表为空,则返回“Nothing”。
'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
【讨论】:
【参考方案6】:我使用以下 vba 代码来确定工作表的整个使用行范围,然后缩短列的选定范围:
Set rUsedRowRange = Selection.Worksheet.UsedRange.Columns( _
Selection.Column - Selection.Worksheet.UsedRange.Column + 1)
反之亦然:
Set rUsedColumnRange = Selection.Worksheet.UsedRange.Rows( _
Selection.Row - Selection.Worksheet.UsedRange.Row + 1)
【讨论】:
【参考方案7】:这个函数给出了使用范围的所有 4 个限制:
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
【讨论】:
UsedRange 的定义还包括格式化的单元格,即使它们是空的。大多数时候,我需要将 UsedRange 定义为非空单元格。【参考方案8】:在 Excel 2013 上的时间相当慢,使用范围非常大,百万行:
26ms Cells.Find xlPrevious 方法(同上)
0.4ms Sheet.UsedRange(随便叫)
0.14ms Counta 二分搜索 + 0.4ms Used Range 开始搜索(12 CountA 调用)
因此,如果担心的话,Find xlPrevious 会很慢。
CountA 二分查找方法是先做一个Used Range。然后将范围切成两半,看看下半部分是否有非空单元格,然后根据需要再次减半。做对是很棘手的。
【讨论】:
【参考方案9】:这是另一个。它查找第一个和最后一个非空单元格,并且构建范围来自这些单元格。这也可以处理您的数据不是矩形且不是从 A1 开始的情况。此外,它还处理合并的单元格,当从宏执行时,.Find 会跳过这些单元格,用于工作表上的 .Cells。
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
【讨论】:
以上是关于获取实际使用范围的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 android 的帐户管理器获取多个范围的身份验证令牌