Range.Address 在公式中使用时被截断(字符串太长)
Range.Address Truncated when Used in Formula (String Too Long)
我有循环遍历用户选择范围的第 5 列的代码,如果第 5 列中的当前单元格符合条件,则将同一行中接下来的 10 个单元格添加到范围中。在一切结束时,如果单元格 A1 为空,它会求和最终范围。
Sub SumItems()
Dim selectedRange As Range
Set selectedRange = Selection
Dim sumRange As Range
Dim i As Long
For i = 1 To selectedRange.Rows.Count
If selectedRange(i, 5) = "Yes" Then
If sumRange Is Nothing Then
Set sumRange = Range(selectedRange(i, 5).Offset(0, 1), selectedRange(i, 5).Offset(0, 10))
Else
Set sumRange = Union(sumRange, Range(selectedRange(i, 5).Offset(0, 1), selectedRange(i, 5).Offset(0, 10)))
End If
End If
Next i
If Not sumRange Is Nothing Then
If IsEmpty(Range("A1")) Then
Range("A1").Formula = "=SUM(" + sumRange.Address(False, False) + ")"
Else
MsgBox "Cannot paste in cell A1, it is not empty."
Exit Sub
End If
Else
MsgBox "No matching rows were found."
Exit Sub
End If
End Sub
我是sheet这个运行长的。所以 sumRange 通常是 sheet 中许多不同区域的联合。我注意到一旦 sumRange.Areas.Count 超过 18,Range("A1").Formula 语句就会出现问题。 sumRange.Address(False, False) 字符串在第 18 个区域后被截断。我相信这是因为 .Address 字符串长度太长,它恰好与这个 sheet.
的 18 个区域重合
我开发了一个临时解决方案,但它限制了子例程可以处理的区域数量,而且笨拙且冗长。如果 sumRange 有超过 18 个区域,我设置了临时范围变量将 sumRange 拆分成 IF 语句现在显示如下:
If Not sumRange Is Nothing Then
If IsEmpty(Range("A1")) Then
If sumRange.Areas.Count > 18 Then
Dim k As Long
Dim tmpSumRange1 As Range
Dim tmpSumRange2 As Range
Dim tmpSumRange3 As Range
' And so on...
For k = 1 To sumRange.Areas.Count
If k <= 18 Then
If tmpSumRange1 Is Nothing Then
Set tmpSumRange1 = sumRange.Areas(k)
Else
Set tmpSumRange1 = Union(tmpSumRange1, sumRange.Areas(k))
End If
ElseIf k > 18 And k <= 36 Then
If tmpSumRange2 Is Nothing Then
Set tmpSumRange2 = sumRange.Areas(k)
Else
Set tmpSumRange2 = Union(tmpSumRange2, sumRange.Areas(k))
End If
ElseIf k > 36 And k <= 54 Then
If tmpSumRange3 Is Nothing Then
Set tmpSumRange3 = sumRange.Areas(k)
Else
Set tmpSumRange3 = Union(tmpSumRange3, sumRange.Areas(k))
End If
ElseIf
' And so on until I get to k = 180...
End If
Next k
If Not tmpSumRange1 Is Nothing And tmpSumRange2 Is Nothing And tmpSumRange3 Is Nothing Then
Range("A1").Formula = "=SUM(" + tmpSumRange1.Address(False, False) + ")"
ElseIf Not tmpSumRange1 Is Nothing And Not tmpSumRange2 Is Nothing And tmpSumRange3 Is Nothing Then
Range("A1").Formula = "=SUM(" + tmpSumRange1.Address(False, False) + "," + tmpSumRange2.Address(False, False) + ")"
ElseIf Not tmpSumRange1 Is Nothing And tmpSumRange2 Is Nothing And Not tmpSumRange3 Is Nothing Then
Range("A1").Formula = "=SUM(" + tmpSumRange1.Address(False, False) + "," + tmpSumRange2.Address(False, False) + "," + tmpSumRange3.Address(False, False) + ")"
ElseIf
' And so on all the way up to tmpSumRange10...
End If
Else
Range("A1").Formula = "=SUM(" + sumRange.Address(False, False) + ")"
End If
Else
MsgBox "Cannot paste in cell A1, it is not empty."
Exit Sub
End If
Else
MsgBox "No matching rows were found."
Exit Sub
End If
我知道必须有比这更好的解决方案。我在搜索中没有找到任何东西。我也没有找到遇到过同样问题的人。我需要 A1 单元格具有 SUM 公式,其中包含范围,否则我将只对子例程中的值求和并插入值而不是公式。
所以有两个独立但可能相关的问题:
Range.Address
最多截断 255 个字符,没有错误。这很奇怪,因为虽然 Excel 足够聪明,不会给你留下会引发 1004 的部分地址字符串,但同时它又愚蠢到允许 Address
截断,这显然会如果用于公式等会产生意想不到的结果
- 如果将字符串传递给
ByVal
(参见 this old thread)以供讨论,Excel 函数的字符串参数有 255 个字符的限制,但我已经摘录了相关内容位,下面)。
Excel function parameters will accept a reference to a string with length of up to 32767 (32k or 2^15 total possible lengths). ... But what if we pass a value instead of a reference?
we can pass a reference to a string up to 32k, we can only pass a string value up to 255
问题似乎是 Formula
长度的结果,但这是一个转移注意力的问题。
您肯定遇到了 Range.Address
的截断问题。
问题:Range.Address
在 255 个字符处截断
由于这种情况悄无声息地发生,因此您基于截断地址构建的任何公式都会受到不利影响;结果不会是您所期望的,因为公式不会代表范围的所有部分!
我已将此记录为 Microsoft 的错误,以防您想关注此问题:
https://github.com/MicrosoftDocs/VBA-Docs/issues/49
同时,幸好解决方案非常简单(虽然不是很容易得出!),看看你能不能适应你的目的,但思路是:
- 创建一个
System.Collections.ArrayList
,我们将所有单独的 Area
地址存储在其中(或者您可以使用 Variant
,但是 ReDim
等等)
- 使用
ToArray()
方法将 ArrayList
转换为变体数组
- 在
Formula
字符串中使用 Join
函数的结果
Sub example()
Dim myNames As Object
Dim formula as String
Dim k As Long
Dim sumRange As Range
Dim thisArea As Range
' Example:
' -- creates a range consisting of 100 Areas
' -- this .Address will truncate to 252 characters!
For k = 1 To 200 Step 2
Set thisArea = Range("A" & k)
If sumRange Is Nothing Then Set sumRange = thisArea
Set sumRange = Union(sumRange, thisArea)
Next
' Iterate the sumRange union and add each Area to an ArrayList
Set myNames = CreateObject("System.Collections.ArrayList")
For Each thisArea In sumRange.Areas
myNames.Add thisArea.Address
Next
' Output to worksheet:
Dim outputCell As Range
Set outputCell = Range("F1")
formula = "=Sum(" & Join(myNames.ToArray(), ",") & ")"
outputCell.Formula = formula
End Sub
并且可以在工作表中看到特别长的公式(Len
== 650):
如果您不习惯使用 ArrayList
,您可以将其强制为 `String:
' Iterate the sumRange union and add each Area to our formula string
formula = "=Sum("
For Each thisArea In sumRange.Areas
formula = formula & thisArea.Address & ","
Next
formula = Left(formula, Len(formula) - 1)
formula = formula & ")"
我有循环遍历用户选择范围的第 5 列的代码,如果第 5 列中的当前单元格符合条件,则将同一行中接下来的 10 个单元格添加到范围中。在一切结束时,如果单元格 A1 为空,它会求和最终范围。
Sub SumItems()
Dim selectedRange As Range
Set selectedRange = Selection
Dim sumRange As Range
Dim i As Long
For i = 1 To selectedRange.Rows.Count
If selectedRange(i, 5) = "Yes" Then
If sumRange Is Nothing Then
Set sumRange = Range(selectedRange(i, 5).Offset(0, 1), selectedRange(i, 5).Offset(0, 10))
Else
Set sumRange = Union(sumRange, Range(selectedRange(i, 5).Offset(0, 1), selectedRange(i, 5).Offset(0, 10)))
End If
End If
Next i
If Not sumRange Is Nothing Then
If IsEmpty(Range("A1")) Then
Range("A1").Formula = "=SUM(" + sumRange.Address(False, False) + ")"
Else
MsgBox "Cannot paste in cell A1, it is not empty."
Exit Sub
End If
Else
MsgBox "No matching rows were found."
Exit Sub
End If
End Sub
我是sheet这个运行长的。所以 sumRange 通常是 sheet 中许多不同区域的联合。我注意到一旦 sumRange.Areas.Count 超过 18,Range("A1").Formula 语句就会出现问题。 sumRange.Address(False, False) 字符串在第 18 个区域后被截断。我相信这是因为 .Address 字符串长度太长,它恰好与这个 sheet.
的 18 个区域重合我开发了一个临时解决方案,但它限制了子例程可以处理的区域数量,而且笨拙且冗长。如果 sumRange 有超过 18 个区域,我设置了临时范围变量将 sumRange 拆分成 IF 语句现在显示如下:
If Not sumRange Is Nothing Then
If IsEmpty(Range("A1")) Then
If sumRange.Areas.Count > 18 Then
Dim k As Long
Dim tmpSumRange1 As Range
Dim tmpSumRange2 As Range
Dim tmpSumRange3 As Range
' And so on...
For k = 1 To sumRange.Areas.Count
If k <= 18 Then
If tmpSumRange1 Is Nothing Then
Set tmpSumRange1 = sumRange.Areas(k)
Else
Set tmpSumRange1 = Union(tmpSumRange1, sumRange.Areas(k))
End If
ElseIf k > 18 And k <= 36 Then
If tmpSumRange2 Is Nothing Then
Set tmpSumRange2 = sumRange.Areas(k)
Else
Set tmpSumRange2 = Union(tmpSumRange2, sumRange.Areas(k))
End If
ElseIf k > 36 And k <= 54 Then
If tmpSumRange3 Is Nothing Then
Set tmpSumRange3 = sumRange.Areas(k)
Else
Set tmpSumRange3 = Union(tmpSumRange3, sumRange.Areas(k))
End If
ElseIf
' And so on until I get to k = 180...
End If
Next k
If Not tmpSumRange1 Is Nothing And tmpSumRange2 Is Nothing And tmpSumRange3 Is Nothing Then
Range("A1").Formula = "=SUM(" + tmpSumRange1.Address(False, False) + ")"
ElseIf Not tmpSumRange1 Is Nothing And Not tmpSumRange2 Is Nothing And tmpSumRange3 Is Nothing Then
Range("A1").Formula = "=SUM(" + tmpSumRange1.Address(False, False) + "," + tmpSumRange2.Address(False, False) + ")"
ElseIf Not tmpSumRange1 Is Nothing And tmpSumRange2 Is Nothing And Not tmpSumRange3 Is Nothing Then
Range("A1").Formula = "=SUM(" + tmpSumRange1.Address(False, False) + "," + tmpSumRange2.Address(False, False) + "," + tmpSumRange3.Address(False, False) + ")"
ElseIf
' And so on all the way up to tmpSumRange10...
End If
Else
Range("A1").Formula = "=SUM(" + sumRange.Address(False, False) + ")"
End If
Else
MsgBox "Cannot paste in cell A1, it is not empty."
Exit Sub
End If
Else
MsgBox "No matching rows were found."
Exit Sub
End If
我知道必须有比这更好的解决方案。我在搜索中没有找到任何东西。我也没有找到遇到过同样问题的人。我需要 A1 单元格具有 SUM 公式,其中包含范围,否则我将只对子例程中的值求和并插入值而不是公式。
所以有两个独立但可能相关的问题:
Range.Address
最多截断 255 个字符,没有错误。这很奇怪,因为虽然 Excel 足够聪明,不会给你留下会引发 1004 的部分地址字符串,但同时它又愚蠢到允许Address
截断,这显然会如果用于公式等会产生意想不到的结果- 如果将字符串传递给
ByVal
(参见 this old thread)以供讨论,Excel 函数的字符串参数有 255 个字符的限制,但我已经摘录了相关内容位,下面)。
Excel function parameters will accept a reference to a string with length of up to 32767 (32k or 2^15 total possible lengths). ... But what if we pass a value instead of a reference?
we can pass a reference to a string up to 32k, we can only pass a string value up to 255
问题似乎是 Formula
长度的结果,但这是一个转移注意力的问题。
您肯定遇到了 Range.Address
的截断问题。
问题:Range.Address
在 255 个字符处截断
由于这种情况悄无声息地发生,因此您基于截断地址构建的任何公式都会受到不利影响;结果不会是您所期望的,因为公式不会代表范围的所有部分!
我已将此记录为 Microsoft 的错误,以防您想关注此问题:
https://github.com/MicrosoftDocs/VBA-Docs/issues/49
同时,幸好解决方案非常简单(虽然不是很容易得出!),看看你能不能适应你的目的,但思路是:
- 创建一个
System.Collections.ArrayList
,我们将所有单独的Area
地址存储在其中(或者您可以使用Variant
,但是ReDim
等等) - 使用
ToArray()
方法将ArrayList
转换为变体数组 - 在
Formula
字符串中使用Join
函数的结果
Sub example()
Dim myNames As Object
Dim formula as String
Dim k As Long
Dim sumRange As Range
Dim thisArea As Range
' Example:
' -- creates a range consisting of 100 Areas
' -- this .Address will truncate to 252 characters!
For k = 1 To 200 Step 2
Set thisArea = Range("A" & k)
If sumRange Is Nothing Then Set sumRange = thisArea
Set sumRange = Union(sumRange, thisArea)
Next
' Iterate the sumRange union and add each Area to an ArrayList
Set myNames = CreateObject("System.Collections.ArrayList")
For Each thisArea In sumRange.Areas
myNames.Add thisArea.Address
Next
' Output to worksheet:
Dim outputCell As Range
Set outputCell = Range("F1")
formula = "=Sum(" & Join(myNames.ToArray(), ",") & ")"
outputCell.Formula = formula
End Sub
并且可以在工作表中看到特别长的公式(Len
== 650):
如果您不习惯使用 ArrayList
,您可以将其强制为 `String:
' Iterate the sumRange union and add each Area to our formula string
formula = "=Sum("
For Each thisArea In sumRange.Areas
formula = formula & thisArea.Address & ","
Next
formula = Left(formula, Len(formula) - 1)
formula = formula & ")"