(编辑:为解决方案增加了 2 个限制)
我有一个表(listobject wise),我需要在其中复制某些行。出于效率原因,我使用 SourceListRow.Range.Value2 = DestListRow.Range.Value2 (一次性复制整个范围)。复制的单元格范围之后的所有公式列都会自动完美地扩展到新行并作用于复制的数据。我在 Windows 上使用 Excel 2010。
但是,尽管我已经在使用这种代码进行了 eons,但我现在才在使用 Range.Value/Range.Value2 时偶然发现了一个奇怪的现象:如果您为其分配一个空字符串,则最终的单元格值不会是一个空字符串,但它将是空的。那就是:数据没有被忠实地复制,并且副本可能与源不同,特别是如果连续的公式在其上使用 ISBLANK 等。因此,在处理副本与源时,相同的公式将产生不同的结果。
请参阅下面的测试代码。打开一个新的空白 Excel 工作簿,转到 VBA,添加一个新模块并添加以下代码:
Sub Test()
ActiveSheet.Range("a1").Formula = "="""""
ActiveSheet.Range("b1").Formula = "=isblank(a1)"
ActiveSheet.Range("c1").Value2 = TypeName(ActiveSheet.Range("a1").Value2)
ActiveSheet.Range("a2").Value2 = ActiveSheet.Range("a1").Value2
ActiveSheet.Range("b2").Formula = "=isblank(a2)"
ActiveSheet.Range("c2").Value2 = TypeName(ActiveSheet.Range("a2").Value2)
ActiveSheet.Range("a3").Value2 = ""
ActiveSheet.Range("b3").Formula = "=isblank(a3)"
ActiveSheet.Range("c3").Value2 = TypeName(ActiveSheet.Range("a3").Value2)
ActiveSheet.Range("a4").Formula = ActiveSheet.Range("a1").Formula
ActiveSheet.Range("b4").Formula = "=isblank(a4)"
ActiveSheet.Range("c4").Value2 = TypeName(ActiveSheet.Range("a4").Value2)
Call ActiveSheet.Range("a1").Copy
Call ActiveSheet.Range("a5").PasteSpecial(xlPasteValues)
ActiveSheet.Range("b5").Formula = "=isblank(a5)"
ActiveSheet.Range("c5").Value2 = TypeName(ActiveSheet.Range("a5").Value2)
End Sub
然后运行它并查看工作表;
该怎么办?
所有想法表示赞赏!
最佳答案
SpecialCells(xlCellTypeBlank) 和 AutoFilter 以不同的方式处理空字符串。您的源数据是否可过滤?如果是这样,您能否使用占位符值,然后将单元格更改为 .Formula = "="""""
复制后?
我获取了您的示例代码并生成了工作簿,然后在其上方添加了一行作为过滤器标题。下面的代码会将所有空字符串更改为“ChangeMe”;然后,您可以复制这些值并使用 Range.Replace 将目标中的所有“ChangeMe”实例替换为“=”“”“”。
Sub Test2()
ActiveSheet.Range("A2:A6").SpecialCells(xlCellTypeBlanks).Interior.Color = 255 'Just to prove that xlCellTypeBlanks only selects actual blanks
ActiveSheet.Range("A1:A6").AutoFilter Field:=1, Criteria1:="=" 'Shows both actual blanks and ZLS/null strings
ActiveSheet.Range("A1:A6").SpecialCells(xlCellTypeBlanks).EntireRow.Hidden = True 'Be able to use SpecialCells(xlCellTypeVisible) to reference all ZLS
ActiveSheet.Range("A2:A6").SpecialCells(xlCellTypeVisible).Value2 = "ChangeMe"
'Now unfilter and unhide your data, copy using .Value2, then .Replace "ChangeMe" with "="""""
End Sub
我认为这可以完成您正在尝试做的事情-让我知道这是否是解决方案的正确方向。
编辑:误解了原始问题。下面的旧答案是不正确的。
虽然不如原始代码高效,但使用 .AutoFilter 比循环遍历许多单元格要高效得多。此外, .AutoFilter 将零长度字符串和空单元格视为相同。
像这样的东西:
Sub CopyAndClearFakeBlanks()
Dim WSSource As Worksheet
Dim WSDest As Worksheet
Dim LRow As Long
Dim LPasteRow As Long
Set WSSource = Sheets("Source Data")
Set WSDest = Sheets("Paste Here")
LRow = WSSource.Range("A:A").Find(what:="*", searchdirection:=xlPrevious).Row 'Note that this will ignore blanks, so you may want to use a different method for finding your last row. Depends on how your users would need the data if there are trailing blanks.
On Error Resume Next
LPasteRow = 2 'Always need at least one row before the data for filtering properly; you can delete after if necessary
LPasteRow = WSDest.Range("A:A").Find(what:="*", searchdirection:=xlPrevious).Row + 1
WSDest.AutoFilterMode = False
On Error GoTo 0 'ofc use proper error handling in your actual code
WSDest.Range("A" & LPasteRow & ":A" & LPasteRow + LRow - 1).Value2 = WSSource.Range("A1:A" & LRow).Value2
WSDest.Range("A" & LPasteRow - 1 & ":A" & LPasteRow + LRow).AutoFilter field:=1, Criteria1:="=" 'Show blank or ZLS only
On Error Resume Next
WSDest.Range("A" & LPasteRow & ":A" & LPasteRow + LRow).SpecialCells(xlCellTypeVisible).Clear 'Turn them into true blanks
WSDest.ShowAllData
WSDest.AutoFilterMode = False
On Error GoTo 0
Set WSDest = Nothing
Set WSSource = Nothing
End Sub
关于vba - 使用 VBA 分配给 .Value 时保留空字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35599770/