VBA宏逐个单元格复制粘贴

huangapple go评论110阅读模式
英文:

VBA macro cell by cell copy paste

问题

我希望你一切都好。

为了我的工作,我制作了一个VBA宏,它的功能是在单元格包含特定公式时将单元格的内容复制并粘贴为数值。

以下是宏的一部分摘录:

  1. Option Explicit
  2. Sub copyPasteValue()
  3. Dim cellContent As String
  4. Dim endRow As Integer
  5. Dim endCol As Integer
  6. Dim r As Integer
  7. Dim c As Integer
  8. Dim activeCellColumn As Integer
  9. Dim activeCellRow As Integer
  10. activeCellColumn = ActiveCell.Column
  11. activeCellRow = ActiveCell.Row
  12. endRow = Cells(Rows.Count, activeCellColumn).End(xlUp).Row
  13. endCol = Cells(activeCellRow, Columns.Count).End(xlToLeft).Column
  14. For c = activeCellColumn To endCol
  15. For r = activeCellRow To endRow
  16. cellContent = Cells(r, c).Formula
  17. If InStr(1, cellContent, "GetCtData") Then
  18. Cells(r, c).Copy
  19. Cells(r, c).PasteSpecial Paste:=xlPasteValues
  20. End If
  21. Next
  22. Next
  23. Cells(activeCellRow, activeCellColumn).Select
  24. If ActiveWorkbook.Name = "VALUE.xlsx" Then
  25. ActiveWorkbook.Save
  26. Else
  27. ActiveWorkbook.SaveAs Filename:="VALUE"
  28. End If
  29. 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.

  1. Option Explicit
  2. Sub copyPasteValue()
  3. Dim cellContent As String
  4. Dim endRow As Integer
  5. Dim endCol As Integer
  6. Dim r As Integer
  7. Dim c As Integer
  8. Dim activeCellColumn As Integer
  9. Dim activeCellRow As Integer
  10. activeCellColumn = ActiveCell.Column
  11. activeCellRow = ActiveCell.Row
  12. endRow = Cells(Rows.Count, activeCellColumn).End(xlUp).Row
  13. endCol = Cells(activeCellRow, Columns.Count).End(xlToLeft).Column
  14. For c = activeCellColumn To endCol
  15. For r = activeCellRow To endRow
  16. cellContent = Cells(r, c).Formula
  17. If InStr(1, cellContent, "GetCtData") Then
  18. Cells(r, c).Copy
  19. Cells(r, c).PasteSpecial Paste:=xlPasteValues
  20. End If
  21. Next
  22. Next
  23. Cells(activeCellRow, activeCellColumn).Select
  24. If ActiveWorkbook.Name = "VALUE.xlsx" Then
  25. ActiveWorkbook.Save
  26. Else
  27. ActiveWorkbook.SaveAs Filename:="VALUE"
  28. End If
  29. 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会查找公式:

  1. Sub replaceFunction()
  2. Const FunctionName = "GetCTData"
  3. With ActiveCell.Cells ' 考虑指定工作表。
  4. Dim hit As Range
  5. Set hit = .Find(What:=FunctionName, _
  6. LookIn:=xlFormulas2, _
  7. LookAt:=xlPart)
  8. If Not hit Is Nothing Then ' 至少找到一个包含公式的单元格
  9. Do
  10. hit.Value = hit.Value ' 替换值
  11. Set hit = .FindNext(hit) ' 查找下一个包含公式的单元格
  12. Loop While Not hit Is Nothing ' ...直到找不到为止。
  13. End If
  14. End With
  15. 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:

  1. Sub replaceFunction()
  2. Const FunctionName = "GetCTData"
  3. With ActiveCell.Cells ' Consider to specify the worksheet.
  4. Dim hit As Range
  5. Set hit = .Find(What:=FunctionName , _
  6. LookIn:=xlFormulas2, _
  7. LookAt:=xlPart)
  8. If Not hit Is Nothing Then ' At least one cell found with formula
  9. Do
  10. hit.Value = hit.Value ' Replace value
  11. Set hit = .FindNext(hit) ' Search next cell with formula
  12. Loop While Not hit Is Nothing ' ...until no more found.
  13. End If
  14. End With
  15. 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",而要使用:

  1. Cells(r, c).Value = Cells(r, c).Value

这将覆盖单元格的值。

你还可以删除存储公式在变量'cellContent'中的那行代码,所以底部的代码块可以重写如下:

  1. For c = activeCellColumn To endCol
  2. For r = activeCellRow To endRow
  3. If InStr(1, Cells(r, c).Formula, "GetCtData") Then
  4. Cells(r, c).Value = Cells(r, c).Value
  5. End If
  6. Next r
  7. 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:

  1. 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:

  1. For c = activeCellColumn To endCol
  2. For r = activeCellRow To endRow
  3. If InStr(1, Cells(r, c).Formula, "GetCtData") Then
  4. Cells(r, c).Value = Cells(r, c).Value
  5. End If
  6. Next r
  7. 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

以下是代码的翻译部分:

  1. 子公式转换为数值()
  2. 常数 FORMULA_IDENTIFIER 作为字符串 = "GetCtData"
  3. Dim ws As Worksheet: Set ws = ActiveSheet ' 改进!
  4. Dim rg As Range: Set rg = ws.UsedRange
  5. Dim rCount As Long: rCount = rg.Rows.Count
  6. Dim cCount As Long: cCount = rg.Columns.Count
  7. Dim rOffset As Long: rOffset = rg.Row - 1
  8. Dim cOffset As Long: cOffset = rg.Column - 1
  9. Dim Data(): Data = rg.Formula
  10. Dim drg As Range, c As Long, r As Long, fr As Long, lr As Long, cc As String
  11. 对于 c = 1 到 cCount
  12. cc = GetColumnString(c + cOffset)
  13. 对于 r = 1 到 rCount
  14. 如果 InStr(Data(r, c), FORMULA_IDENTIFIER) > 0 Then
  15. 如果 fr = 0 则 fr = r + rOffset
  16. lr = r + rOffset
  17. 否则
  18. 如果 fr > 0 则 CombineAndReset drg, fr, ws, lr, cc
  19. 结束 如果
  20. 下一个 r
  21. 如果 fr > 0 则 CombineAndReset drg, fr, ws, lr, cc
  22. 下一个 c
  23. 如果 drg 为 Nothing
  24. MsgBox "未找到包含 """ & FORMULA_IDENTIFIER _
  25. & """ 的公式。未执行任何操作。", vbExclamation
  26. 退出子程序
  27. 结束 如果
  28. 粘贴区域数值 drg
  29. With ws.Parent
  30. 如果 .Name = "VALUE.xlsx" 则 .Save Else .SaveAs 文件名 = "VALUE"
  31. 结束 With
  32. MsgBox "包含 """ & FORMULA_IDENTIFIER _
  33. & """ 的公式已替换为数值。", vbInformation
  34. 结束 子程序

以下是帮助部分的翻译:

  1. 函数 GetColumnString(ByVal ColumnNumber As Long) As String
  2. Dim Remainder As Long
  3. Remainder = (ColumnNumber - 1) Mod 26
  4. GetColumnString = Chr(Remainder + 65) & GetColumnString
  5. ColumnNumber = Int((ColumnNumber - Remainder) \ 26)
  6. 直到 ColumnNumber = 0
  7. 结束 函数
  8. 子程序 CombineAndReset( _
  9. 通过引用 urg As Range, _
  10. 通过引用 fr As Long, _
  11. ByVal ws As Worksheet, _
  12. ByVal lr As Long, _
  13. ByVal cc As String)
  14. 合并范围 urg, ws.Range(cc & fr & ":" & cc & lr)
  15. fr = 0
  16. 结束 子程序
  17. 子程序 CombineRanges(通过引用 urg As Range, ByVal arg As Range)
  18. 如果 urg Nothing Set urg = arg Else Set urg = Union(urg, arg)
  19. 结束 子程序
  20. 子程序 粘贴区域数值(ByVal rg As Range)
  21. Dim arg As Range
  22. 对于 每个 arg rg.Areas arg.Value = arg.Value: 下一个 arg
  23. 结束 子程序
英文:

Formulas To Values

Main

<!-- language: lang-vb -->

  1. Sub FormulasToValues()
  2. Const FORMULA_IDENTIFIER As String = &quot;GetCtData&quot;
  3. Dim ws As Worksheet: Set ws = ActiveSheet &#39; improve!
  4. Dim rg As Range: Set rg = ws.UsedRange
  5. Dim rCount As Long: rCount = rg.Rows.Count
  6. Dim cCount As Long: cCount = rg.Columns.Count
  7. Dim rOffset As Long: rOffset = rg.Row - 1
  8. Dim cOffset As Long: cOffset = rg.Column - 1
  9. Dim Data(): Data = rg.Formula
  10. Dim drg As Range, c As Long, r As Long, fr As Long, lr As Long, cc As String
  11. For c = 1 To cCount
  12. cc = GetColumnString(c + cOffset)
  13. For r = 1 To rCount
  14. If InStr(Data(r, c), FORMULA_IDENTIFIER) &gt; 0 Then
  15. If fr = 0 Then fr = r + rOffset
  16. lr = r + rOffset
  17. Else
  18. If fr &gt; 0 Then CombineAndReset drg, fr, ws, lr, cc
  19. End If
  20. Next r
  21. If fr &gt; 0 Then CombineAndReset drg, fr, ws, lr, cc
  22. Next c
  23. If drg Is Nothing Then
  24. MsgBox &quot;No formulas containing &quot;&quot;&quot; &amp; FORMULA_IDENTIFIER _
  25. &amp; &quot;&quot;&quot; found. No action taken.&quot;, vbExclamation
  26. Exit Sub
  27. End If
  28. PasteAreasValues drg
  29. With ws.Parent
  30. If .Name = &quot;VALUE.xlsx&quot; Then .Save Else .SaveAs Filename:=&quot;VALUE&quot;
  31. End With
  32. MsgBox &quot;Formulas containing &quot;&quot;&quot; &amp; FORMULA_IDENTIFIER _
  33. &amp; &quot;&quot;&quot; replaced with values.&quot;, vbInformation
  34. End Sub

The Help

<!-- language: lang-vb -->

  1. Function GetColumnString(ByVal ColumnNumber As Long) As String
  2. Dim Remainder As Long
  3. Do
  4. Remainder = (ColumnNumber - 1) Mod 26
  5. GetColumnString = Chr(Remainder + 65) &amp; GetColumnString
  6. ColumnNumber = Int((ColumnNumber - Remainder) \ 26)
  7. Loop Until ColumnNumber = 0
  8. End Function
  9. Sub CombineAndReset( _
  10. ByRef urg As Range, _
  11. ByRef fr As Long, _
  12. ByVal ws As Worksheet, _
  13. ByVal lr As Long, _
  14. ByVal cc As String)
  15. CombineRanges urg, ws.Range(cc &amp; fr &amp; &quot;:&quot; &amp; cc &amp; lr)
  16. fr = 0
  17. End Sub
  18. Sub CombineRanges(ByRef urg As Range, ByVal arg As Range)
  19. If urg Is Nothing Then Set urg = arg Else Set urg = Union(urg, arg)
  20. End Sub
  21. Sub PasteAreasValues(ByVal rg As Range)
  22. Dim arg As Range
  23. For Each arg In rg.Areas: arg.Value = arg.Value: Next arg
  24. End Sub

huangapple
  • 本文由 发表于 2023年2月27日 17:43:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75578844.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定