英文:
VBA macro cell by cell copy paste
问题
我希望你一切都好。
为了我的工作,我制作了一个VBA宏,它的功能是在单元格包含特定公式时将单元格的内容复制并粘贴为数值。
以下是宏的一部分摘录:
Option Explicit
Sub copyPasteValue()
Dim cellContent As String
Dim endRow As Integer
Dim endCol As Integer
Dim r As Integer
Dim c As Integer
Dim activeCellColumn As Integer
Dim activeCellRow As Integer
activeCellColumn = ActiveCell.Column
activeCellRow = ActiveCell.Row
endRow = Cells(Rows.Count, activeCellColumn).End(xlUp).Row
endCol = Cells(activeCellRow, Columns.Count).End(xlToLeft).Column
For c = activeCellColumn To endCol
For r = activeCellRow To endRow
cellContent = Cells(r, c).Formula
If InStr(1, cellContent, "GetCtData") Then
Cells(r, c).Copy
Cells(r, c).PasteSpecial Paste:=xlPasteValues
End If
Next
Next
Cells(activeCellRow, activeCellColumn).Select
If ActiveWorkbook.Name = "VALUE.xlsx" Then
ActiveWorkbook.Save
Else
ActiveWorkbook.SaveAs Filename:="VALUE"
End If
End Sub
这个宏运行速度非常慢,对于某些工作表可能需要超过1小时。有没有人有办法提高速度?
提前感谢你的帮助。
英文:
I hope you are doing great.
For my work I made a VBA macro which consist on copy pasting in value the content of a cell if the the cell containt a certain formula.
Please find below an extract of the macro.
Option Explicit
Sub copyPasteValue()
Dim cellContent As String
Dim endRow As Integer
Dim endCol As Integer
Dim r As Integer
Dim c As Integer
Dim activeCellColumn As Integer
Dim activeCellRow As Integer
activeCellColumn = ActiveCell.Column
activeCellRow = ActiveCell.Row
endRow = Cells(Rows.Count, activeCellColumn).End(xlUp).Row
endCol = Cells(activeCellRow, Columns.Count).End(xlToLeft).Column
For c = activeCellColumn To endCol
For r = activeCellRow To endRow
cellContent = Cells(r, c).Formula
If InStr(1, cellContent, "GetCtData") Then
Cells(r, c).Copy
Cells(r, c).PasteSpecial Paste:=xlPasteValues
End If
Next
Next
Cells(activeCellRow, activeCellColumn).Select
If ActiveWorkbook.Name = "VALUE.xlsx" Then
ActiveWorkbook.Save
Else
ActiveWorkbook.SaveAs Filename:="VALUE"
End If
End Sub
The macro is very slow and can take up to more than 1 hour per sheet for certain work. Does anyone have an idea on how to increase the speed ?
Thank you in advance for your help.
答案1
得分: 1
代替循环所有单元格(这需要时间),我建议使用“查找”功能,这样Excel会查找公式:
Sub replaceFunction()
Const FunctionName = "GetCTData"
With ActiveCell.Cells ' 考虑指定工作表。
Dim hit As Range
Set hit = .Find(What:=FunctionName, _
LookIn:=xlFormulas2, _
LookAt:=xlPart)
If Not hit Is Nothing Then ' 至少找到一个包含公式的单元格
Do
hit.Value = hit.Value ' 替换值
Set hit = .FindNext(hit) ' 查找下一个包含公式的单元格
Loop While Not hit Is Nothing ' ...直到找不到为止。
End If
End With
End Sub
这看起来有点奇怪,但hit.Value = hit.Value
将公式替换为其实际值。
英文:
Instead looping over all cells (which is time consuming), I would suggest to use the Find
function so Excel looks for the formula:
Sub replaceFunction()
Const FunctionName = "GetCTData"
With ActiveCell.Cells ' Consider to specify the worksheet.
Dim hit As Range
Set hit = .Find(What:=FunctionName , _
LookIn:=xlFormulas2, _
LookAt:=xlPart)
If Not hit Is Nothing Then ' At least one cell found with formula
Do
hit.Value = hit.Value ' Replace value
Set hit = .FindNext(hit) ' Search next cell with formula
Loop While Not hit Is Nothing ' ...until no more found.
End If
End With
End Sub
It may look a little bit strange, but hit.Value = hit.Value
replaces the formula with it's actual value.
答案2
得分: 0
循环查找"GetCtData"似乎是不可避免的,但你应该避免使用剪贴板
即,不要使用你的两行"Copy"和"PasteSpecial",而要使用:
Cells(r, c).Value = Cells(r, c).Value
这将覆盖单元格的值。
你还可以删除存储公式在变量'cellContent'中的那行代码,所以底部的代码块可以重写如下:
For c = activeCellColumn To endCol
For r = activeCellRow To endRow
If InStr(1, Cells(r, c).Formula, "GetCtData") Then
Cells(r, c).Value = Cells(r, c).Value
End If
Next r
Next c
避免使用剪贴板将节省大量时间,而且也更不容易出错(避免使用剪贴板是一个通用的规则,值得一读)。
英文:
Looping to look for "GetCtData" sounds unavoidable but what you should do is avoid the clipboard
I.e. instead of your two lines "...Copy" and "...PasteSpecial", use:
Cells(r, c).Value = Cell(r, c).Value
...which overwrites the cell with its own value
You can also cut out the line that stores the formula in the variable 'cellContent', so the bottom block of code can be re-written as follows:
For c = activeCellColumn To endCol
For r = activeCellRow To endRow
If InStr(1, Cells(r, c).Formula, "GetCtData") Then
Cells(r, c).Value = Cells(r, c).Value
End If
Next r
Next c
Bypassing the clipboard will save a fair amount of time, and is also less buggy (worth a read on avoiding the clipboard as a general rule)
答案3
得分: 0
以下是代码的翻译部分:
子公式转换为数值()
常数 FORMULA_IDENTIFIER 作为字符串 = "GetCtData"
Dim ws As Worksheet: Set ws = ActiveSheet ' 改进!
Dim rg As Range: Set rg = ws.UsedRange
Dim rCount As Long: rCount = rg.Rows.Count
Dim cCount As Long: cCount = rg.Columns.Count
Dim rOffset As Long: rOffset = rg.Row - 1
Dim cOffset As Long: cOffset = rg.Column - 1
Dim Data(): Data = rg.Formula
Dim drg As Range, c As Long, r As Long, fr As Long, lr As Long, cc As String
对于 c = 1 到 cCount
cc = GetColumnString(c + cOffset)
对于 r = 1 到 rCount
如果 InStr(Data(r, c), FORMULA_IDENTIFIER) > 0 Then
如果 fr = 0 则 fr = r + rOffset
lr = r + rOffset
否则
如果 fr > 0 则 CombineAndReset drg, fr, ws, lr, cc
结束 如果
下一个 r
如果 fr > 0 则 CombineAndReset drg, fr, ws, lr, cc
下一个 c
如果 drg 为 Nothing 则
MsgBox "未找到包含 """ & FORMULA_IDENTIFIER _
& """ 的公式。未执行任何操作。", vbExclamation
退出子程序
结束 如果
粘贴区域数值 drg
With ws.Parent
如果 .Name = "VALUE.xlsx" 则 .Save Else .SaveAs 文件名 = "VALUE"
结束 With
MsgBox "包含 """ & FORMULA_IDENTIFIER _
& """ 的公式已替换为数值。", vbInformation
结束 子程序
以下是帮助部分的翻译:
函数 GetColumnString(ByVal ColumnNumber As Long) As String
Dim Remainder As Long
做
Remainder = (ColumnNumber - 1) Mod 26
GetColumnString = Chr(Remainder + 65) & GetColumnString
ColumnNumber = Int((ColumnNumber - Remainder) \ 26)
直到 ColumnNumber = 0
结束 函数
子程序 CombineAndReset( _
通过引用 urg As Range, _
通过引用 fr As Long, _
ByVal ws As Worksheet, _
ByVal lr As Long, _
ByVal cc As String)
合并范围 urg, ws.Range(cc & fr & ":" & cc & lr)
fr = 0
结束 子程序
子程序 CombineRanges(通过引用 urg As Range, ByVal arg As Range)
如果 urg 为 Nothing 则 Set urg = arg Else Set urg = Union(urg, arg)
结束 子程序
子程序 粘贴区域数值(ByVal rg As Range)
Dim arg As Range
对于 每个 arg 在 rg.Areas 中:arg.Value = arg.Value: 下一个 arg
结束 子程序
英文:
Formulas To Values
Main
<!-- language: lang-vb -->
Sub FormulasToValues()
Const FORMULA_IDENTIFIER As String = "GetCtData"
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim rg As Range: Set rg = ws.UsedRange
Dim rCount As Long: rCount = rg.Rows.Count
Dim cCount As Long: cCount = rg.Columns.Count
Dim rOffset As Long: rOffset = rg.Row - 1
Dim cOffset As Long: cOffset = rg.Column - 1
Dim Data(): Data = rg.Formula
Dim drg As Range, c As Long, r As Long, fr As Long, lr As Long, cc As String
For c = 1 To cCount
cc = GetColumnString(c + cOffset)
For r = 1 To rCount
If InStr(Data(r, c), FORMULA_IDENTIFIER) > 0 Then
If fr = 0 Then fr = r + rOffset
lr = r + rOffset
Else
If fr > 0 Then CombineAndReset drg, fr, ws, lr, cc
End If
Next r
If fr > 0 Then CombineAndReset drg, fr, ws, lr, cc
Next c
If drg Is Nothing Then
MsgBox "No formulas containing """ & FORMULA_IDENTIFIER _
& """ found. No action taken.", vbExclamation
Exit Sub
End If
PasteAreasValues drg
With ws.Parent
If .Name = "VALUE.xlsx" Then .Save Else .SaveAs Filename:="VALUE"
End With
MsgBox "Formulas containing """ & FORMULA_IDENTIFIER _
& """ replaced with values.", vbInformation
End Sub
The Help
<!-- language: lang-vb -->
Function GetColumnString(ByVal ColumnNumber As Long) As String
Dim Remainder As Long
Do
Remainder = (ColumnNumber - 1) Mod 26
GetColumnString = Chr(Remainder + 65) & GetColumnString
ColumnNumber = Int((ColumnNumber - Remainder) \ 26)
Loop Until ColumnNumber = 0
End Function
Sub CombineAndReset( _
ByRef urg As Range, _
ByRef fr As Long, _
ByVal ws As Worksheet, _
ByVal lr As Long, _
ByVal cc As String)
CombineRanges urg, ws.Range(cc & fr & ":" & cc & lr)
fr = 0
End Sub
Sub CombineRanges(ByRef urg As Range, ByVal arg As Range)
If urg Is Nothing Then Set urg = arg Else Set urg = Union(urg, arg)
End Sub
Sub PasteAreasValues(ByVal rg As Range)
Dim arg As Range
For Each arg In rg.Areas: arg.Value = arg.Value: Next arg
End Sub
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论