使用InStr或Left / Right在反向循环中检查变量

时间:2018-11-30 18:48:36

标签: excel vba

在工作中,我有一个重复的任务,即遍历帐户活动和更改的列表,在这些更改中,我必须删除执行维护所不需要的空格和行。对于其中的80%,我能够为每个循环工作一个非常细腻但有效的循环。 示例:

import pandas as pd
import numpy as np
import itertools
N_t = 5
N_e = 2
classes = tuple(list(itertools.product([0, 1], repeat=N_e)))
N_c = len(classes)
noise = np.random.randint(0, 10, size=(N_c, N_t))
df = pd.DataFrame(noise, index=classes)
df

        0   1   2   3   4
0   0   5   9   4   1   2
    1   2   2   7   9   9
1   0   1   7   3   6   9
    1   4   9   8   2   9

# should be shown as
        0   1   2   3   4
0   0   5   9   4   1   2
0   1   2   2   7   9   9
1   0   1   7   3   6   9
1   1   4   9   8   2   9

子字符串是每种交易类型的描述性标题行。我遇到的一个问题是可变的,而其他的则不是。它可以是9行或6行,也可以是正数或负数,但每种可能性都带有相同的标题行。 根据我能找到的所有答案,我需要使用一个循环,从下到上移动。我无法通过InStr或向左/向右触发它。

这是我现在正在尝试的简化版本:

For Each c In ActiveSheet.UsedRange
If InStr(1, c.Value, SubString7) = 1 Then   ' find earn lines and remove
c.EntireRow.Offset(1).Delete
c.EntireRow.Clear
c.EntireRow.Offset(-1).Delete
End If

Next

我最初的第一条If行是:

    lr = Range("A" & Rows.Count).End(xlUp).Row
        For rowcounter = lr To 0 Step -1
          If VBA.Strings.Left(Cells(rowcounter).Value, 11) Like "Earn Manual" Then
              If VBA.Strings.Left(Cells(rowcounter + 5).Value, 1) = "-" Then 
                  If VBA.Strings.Left(Cells(rowcounter + 6).Value, 3) = "AVG" Then 
                  Cells(rowcounter).EntireRow.Offset(5).Delete 'this, several more times with different offsets for the required lines
                  Else
                  Cells(rowcounter).EntireRow.Offset(5).Delete 'different ones, finalizing removals on the negative value items
                  End if
              Else
                  If VBA.Strings.Left(Cells(rowcounter + 6).Value, 3) = "AVG" Then
                  Cells(rowcounter).EntireRow.Offset(5).Delete 'again, but with different offsets
                  Else 'There is one line for these that I have to split into two lines, not sure if this will even work as I cannot get it to trigger
                  Cells(rowcounter).EntireRow.Offset(8).Delete
                  Cells(rowcounter).EntireRow.Offset(7).Delete
                  Cells(rowcounter + 4).Value = VBA.Strings.Right(Cells(rowcounter + 3).Value, 25)
                  Cells(rowcounter + 3).Value = VBA.Strings.Left(Cells(rowcounter + 3).Value, 13)
                  End if 
              End If
          End If

Next Rowcounter

我尝试切换为If InStr(1, Cells(rowcounter).Value, SubString8) = 1 Then 和“赞”,但仍然没有骰子。

试图提供输入/输出示例

样本数据:
sample data

A列的目标输出:

Retained Data

再次更新,新的和改进的代码仍然失败:

Left()

1 个答案:

答案 0 :(得分:0)

我无法100%正确地得到它,因为它是基于OP的新代码和改进代码的,这在逻辑上存在一些缺陷。我的目标是简化整体语法,以使其更容易理解。

删除带有偏移值的问题是这些值会在您身上移动。我的解决方案是合并要删除的所有行,然后在循环完成后删除它们。这不仅效率更高,而且还允许我们从上到下循环。这使代码更易于遵循。

以联合方式进行范围调整时,必须首先进行测试以查看要删除的目标范围是否为Nothing。如果目标范围是“无”,则将其设置为新范围,否则我们将两个范围合并。我编写了一个子例程UnionRange(),这样我们就不必在每次需要执行Union时都重复此过程。

WithRange.Offset()Range.Resize()用于简化语法。我觉得这比在范围内连接地址更干净(例如Range(“ A”&i + 5)和Range(“ A”&i,“ A”&i + 8))。

Sub CleanUp()
    With ThisWorkbook.Worksheets("Sheet1")
        Dim r As Long
        Dim rUnion As Range
        For r = 1 To .Cells(.Rows.Count, 1).End(xlUp).Row
            With .Cells(r, 1)
                If .Value = "" Then
                    UnionRange rUnion, .Offset(0)
                ElseIf .Value Like "Earn Manual*" Then
                    If .Offset(6).Value Like "Avg*" Then    ' shows AVG, negative value
                        UnionRange rUnion, .Offset(8)
                    Else                              ' no AVG, negative value
                        UnionRange rUnion, .Offset(5)
                    End If
                Else
                    'This can't be right
                    If .Offset(6).Value Like "Avg*" Then 'If Like "Avg*" Then Delete These Cells
                        UnionRange rUnion, .Resize(3)
                        UnionRange rUnion, .Offset(5)
                    Else 'Hell If Not Like "Avg*" Then Delete The Same Cells Anyway
                        UnionRange rUnion, .Resize(3)
                        UnionRange rUnion, .Offset(5)
                    End If
                End If
            End With
        Next
    End With

    If Not rUnion Is Nothing Then
        Application.ScreenUpdating = False
        rUnion.EntireRow.Delete
    End If
End Sub

Sub UnionRange(ByRef rUnion As Range, ByRef Cell As Range)
    If rUnion Is Nothing Then
        Set rUnion = Cell
    Else
        Set rUnion = Union(rUnion, Cell)
    End If
End Sub