简体   繁体   English

使用 Excel 的 vba 在公式中向左移动一列

[英]Move one column to the left inside a formula using Excel's vba

I have some cells that contain the following formulas (there are a lot more but I'm just showing one as an example, they all follow the same pattern of using basic operations like + or - with the values inside certain cells)我有一些包含以下公式的单元格(还有很多,但我只是以一个为例,它们都遵循使用 + 或 - 等基本操作的相同模式以及某些单元格内的值)

=+$O11+$N11+$M11

and I need to move every column one to the left as to end up with something like我需要将每一列向左移动一个,最终得到类似的东西

=+$N11+$M11+$L11

the thing is that I have already written code that detects whether or not a cell has a formula or only a value问题是我已经编写了检测单元格是否有公式或只有值的代码

for each cell in Selection // im using a selection for testing purposes only
   if cell.hasFormula() = true then
   end if
next cell

but I'm still figuring out how to shift all the column references one to the left, the only code I have written trying to do that does not work但我仍在弄清楚如何将所有列引用向左移动一个,我写的唯一代码试图这样做是行不通的

auxiliary = "=offset(" + Replace(cell.formula, "=","") + ",0,1)"
cell.formula = auxiliary

Update 1更新 1

There are formulas that only use 1 cell to check either if its set or not, up to 8 referenced cells.有些公式只使用 1 个单元格来检查其是否设置,最多 8 个引用的单元格。 Numbers or references move around those 2 previously stated numbers数字或参考在这 2 个先前声明的数字周围移动

Update 2更新 2

I found the following property named Precedents that is returning the range of references, at least that's what doing if I apply it to a formulated reference ie with the first example, precedents would return $O$11:$M$11我发现以下名为 Precedents 的属性返回了引用范围,至少如果我将它应用于公式化的引用就是这样做的,即在第一个示例中,precedents 将返回 $O$11:$M$11

Update 3更新 3

There are two more types of formulas besides the one stated above, the first is formulas with a Sum ie除了上述之外,还有两种类型的公式,第一种是带有 Sum 的公式,即

=Sum($R20:$AC20)

And with IFs ie和 IF 即

=IF($BG20=0,1," ")

All of the cell references inside of this formulas must be shifted to the Left by 1.此公式中的所有单元格引用都必须向左移动 1。

So long as you are overwriting the same cell, you can try: 只要您覆盖同一单元格,就可以尝试:

Option Explicit
Sub shiftLeft()
    Dim f As String
    Dim origCol As Long, newCol As Long
    Dim r As Range, c As Range
    Dim re As Object, mc As Object, m As Object
    Dim I As Long, startNum As Long, numChars As Long

Set re = CreateObject("vbscript.regexp")
With re
    .Global = True
    .Pattern = "C\[?(-?\d+)"
End With

Set r = Range(Cells(1, 9), Cells(Rows.Count, 9).End(xlUp))
For Each c In r
    If c.HasFormula = True Then
        f = c.FormulaR1C1
        'Debug.Print f, c.Formula
        If re.test(f) = True Then
            Set mc = re.Execute(f)
            For I = mc.Count To 1 Step -1
                Set m = mc(I - 1)
                startNum = m.firstindex + 1 + Len(m) - Len(m.submatches(0))
                numChars = Len(m.submatches(0))
                newCol = m.submatches(0) - 1
                f = WorksheetFunction.Replace(f, startNum, numChars, newCol)
            Next I
        End If
    End If
    c.FormulaR1C1 = f
    'Debug.Print f, c.Formula & vbLf
Next c

End Sub

I use regular expressions to find the column designation which will be in the form of Cnn or C[nn] or C[-nn] We can then subtract one from nn to get the new column number Use the location and length to decide where to place the replacement. 我使用正则表达式来查找将以CnnC[nn]C[-nn]形式出现的列名称。然后,我们可以从nn减去一个来获得新的列号。放置替换物。

If the resultant formula refers to a column to the left of column A , this macro will terminate with a run-time error 1004 . 如果结果公式引用的是列A左侧的一列,则此宏将终止,并显示运行时错误1004 You should probably add a routine depending on what you want to do in that instance. 您可能应该根据在该实例中要执行的操作添加一个例程。

EDIT: I did not test to ensure that Cnn is a valid cell address and not a NAME . 编辑: 我没有测试以确保Cnn是有效的单元格地址,而不是NAME Mostly that won't matter unless you have some very unusual names (eg Cnnnnnnnnn ) since names that conflict with cell addresses will be rejected, but if your C is followed by a large number, it may be accepted. 除非您有一些非常不寻常的名称(例如Cnnnnnnnnn ),否则大多数情况都没有关系,因为与单元地址冲突的名称将被拒绝,但是如果您的C后面跟着一个大数字,则可以接受。 That test could be added if it might be an issue. 如果可能有问题,可以添加该测试。

you could use a helper temporary sheet to copy/paste data/formula to, delete first column (and have formula shift one column left) and paste back: 您可以使用辅助程序临时表将数据/公式复制/粘贴到其中,删除第一列(并使公式向左移一列)并粘贴回:

Dim tmpSht As Worksheet
Dim rng As Range

Set rng = Selection
Set tmpSht = Worksheets.Add
With rng
    .Copy Destination:=tmpSht.Range(rng.Address).Offset(, -1)
End With

With tmpSht
    .Columns(1).Delete
    .Range(rng.Address).Offset(, -2).Copy Destination:=rng
    Application.DisplayAlerts = False
    .Delete
    Application.DisplayAlerts = True
End With

or you could act on every single cell with formula: 或者您可以使用公式对每个单元格进行操作:

Sub main()
    Dim tmpSht As Worksheet
    Dim cell As Range, rng As Range

    Set rng = Selection
    Set tmpSht = Worksheets.Add ' add a "helper" temporary worksheet

    For Each cell In rng.SpecialCells(xlCellTypeFormulas) ' loop through selection cells containing a formula
        ShiftFormulaOneColumnToTheLeft cell, tmpSht
    Next

    'delete "helper" worksheet
    Application.DisplayAlerts = False
    .Delete
    Application.DisplayAlerts = True
End Sub

Sub ShiftFormulaOneColumnToTheLeft(rng As Range, hlpSht As Worksheet)
    rng.Copy Destination:=hlpSht.Range("B1") ' copy passed range and paste it to passed "helper" worksheet range "B1"

    With hlpSht ' reference passed "helper" worksheet
        .Columns(1).Delete ' delete referenced worksheet first column and have all its formulas shift one column to the left
        .Range("A1").Copy Destination:=rng ' copy "helper" worksheet "A1" cell (where previous "B1" has ended to) content  to passed range
    End With
End Sub

This would work to move/shift the formula's references as intended:这可以按预期移动/移动公式的引用:

strFormula$ = "=+$O11+$N11+$M11"
strFormulaMoved$ = Application.ConvertFormula(Application.ConvertFormula(Selection.Formula, XlReferenceStyle.xlA1, XlReferenceStyle.xlR1C1, XlReferenceType.xlRelative, Selection), XlReferenceStyle.xlR1C1, XlReferenceStyle.xlA1, XlReferenceType.xlRelRowAbsColumn, Selection.Offset(0, -1))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM