簡體   English   中英

在Excel VBA中使用'For Each'循環和'If'語句時出錯

[英]Error in using 'For Each' loop and 'If' statement in excel vba

Excel VBA-使用“ For Each”循環和“ If”語句時出錯。

我有一本Excel工作簿; 有兩張紙:

第一頁是“司法管轄區”,其中包含三列:

國家(B欄),州(C欄)和城市(D欄)

此工作表每個城市都有一個條目。

但是,由於每個城市都在單獨的行中列出,因此州和國家(城市所屬)的名稱可以在多行中重復。

例如:

Col B   |  Col C   |   Col D   |
--------------------------------
U.S.    | New York |  Buffalo  |
U.S.    | New York | Manhattan |

(這是我的兩行)

我還有另一張紙:Sheet1;

這里我也有相同的三列; (以及其他20列)

我將使用“管轄權”表中的三列來驗證這三列。 (Sheet1中僅列出了很少的“管轄區”;這些管轄區可以按任何順序排列,並且可以適用於任何國家/地區)

驗證規則是:

1)國家

  • 國家/地區名稱只能是一個值。
  • 應與管轄權表中“國家/地區”列下的名稱匹配。
  • 案件應忽略(大寫/小寫)

2)狀態

  • 可以有一個或多個僅用分號分隔的值(要用分號分隔這些值,我編寫了不同的代碼,效果很好)
  • 該單元格中的條目甚至可以是“全部”
  • 所有州名稱應與“管轄權”表“州”列中列出的州相匹配。 (如果列出了多個條目,則應首先根據分號(分號)將其分開,然后進行比較)
  • 案件應忽略(大寫/小寫); 狀態名稱前后的多余空格應修剪。

3)城市

  • 只能有一個或多個用分號分隔的值。
  • 該單元格中的條目也可以是“全部”。
  • 所有城市名稱應與“管轄權”表中“城市”列下列出的城市相匹配。 (如果列出了多個條目,則應首先根據分號(分號)將其分開,然后進行比較)
  • 案件應忽略(大寫/小寫); 狀態名稱前后的多余空格應修剪。

我有以下代碼可以正確驗證國家,州和城市。 (從語言上講-拼寫。)

Col B   |  Col C   |       Col D        |
-----------------------------------------
U.S.    | New York | Buffalo            |
U.S.    | New York | Manhattan; Buffalo |
India   | Karnataka| Bangalore          |

此外,它還可以正確驗證層次結構。

Dim nLastRow As Long
Dim nLastRowSheet2 As Long
Dim rngFnder As Range
Dim strFndAddress As String

Dim stString As String
Dim stArray() As String

'Get the last row
'Dim lastRow As Integer
nLastRow = Sheets("Sheet1").Cells(Rows.Count, 2).End(xlUp).Row
nLastRowSheet2 = Sheets("Jurisdictions").Cells(Rows.Count, 2).End(xlUp).Row

Dim c As Range
Dim d As Range
Dim e As Variant

'Turn screen updating off to speed up macro code.
'User won't be able to see what the macro is doing, but it will run faster.
Application.ScreenUpdating = False

For Each c In Worksheets("Sheet1").Range("D2:D" & nLastRow)
stString = c
stArray() = Split(stString, ";")
For Each e In stArray()
    e = Trim(e)

    strFndAddress = ""
    On Error Resume Next

        Set rngFnder = Sheets("Jurisdictions").Range("D2:D" & nLastRowSheet2).Find(e)

        If rngFnder Is Nothing And c <> "All" Then
            c.Interior.Color = vbRed

        Else
            strFndAddress = rngFnder.Address
            Do
                If c.Offset(, -1) = rngFnder.Offset(, -1) And c.Offset(, -2) = rngFnder.Offset(, -2) Then
                    strFndAddress = ""
                    Exit Do
                Else

                    Set rngFnder = Sheets("Jurisdictions").Range("D2:D" & nLastRowSheet2).FindNext(rngFnder)

                End If
            Loop While Not rngFnder Is Nothing And rngFnder.Address <> strFndAddress
        End If

        If rngFnder.Address = strFndAddress Then
            c.Interior.Color = vbRed
        End If
    On Error GoTo 0
    Set c = Nothing
    strFndAddress = ""
Next
Next

現在我還有其他要求

  • 在“狀態”單元格中可以列出僅用分號分隔的多個狀態。
  • 如果在狀態下列出了多個狀態; 那么City的相鄰單元格應該(強制)僅具有值“ All”。 (就像列出了多個狀態一樣,以上代碼無法正確驗證層次結構)
  • 狀態單元格的值可能為“所有”(即所有狀態;沒有單獨列出的狀態)
  • 如果狀態單元格的值為“全部”,則相鄰的城市單元格(強制性)應僅具有值“全部”。
  • 在某些情況下,“州”下會列出一個州的值,但相鄰的城市單元格仍可以具有“全部”值

為了實現上述要求,我添加了以下代碼

For Each c In Worksheets("Sheet1").Range("D2:D" & nLastRow)
        If c.Offset(, -1) = "All" And c = "All" Then
            c.Interior.Color = vbWhite
        End If
Next

和...

For Each c In Worksheets("Sheet1").Range("D2:D" & nLastRow)
    If c = "All" Then
    stString = c.Offset(, -1)
    stArray() = Split(stString, ";")
    End If
        For Each e In stArray()
        e = Trim(e)
        strFndAddress = ""

        On Error Resume Next

        Set rngFnder = Sheets("Jurisdictions").Range("C2:C" & nLastRowSheet2).Find(e)

        If rngFnder Is Nothing And e <> "All" Then
            'c.Interior.Color = c.Interior.Color (Do Nothing)
        Else
            strFndAddress = rngFnder.Address
            Do
            If c.Offset(, -2) = rngFnder.Offset(, -2) Then
                    strFndAddress = ""
                    c.Interior.Color = vbWhite
                    Exit Do
            Else
                    Set rngFnder = Sheets("Jurisdictions").Range("C2:C" & nLastRowSheet2).FindNext(rngFnder)

            End If
            Loop While Not rngFnder Is Nothing And rngFnder.Address <> strFndAddress
        End If

        If rngFnder.Address = strFndAddress Then
        'c.Interior.Color = c.Interior.Color (Do Nothing)
        End If
        On Error GoTo 0
        Set c = Nothing
        strFndAddress = ""

    Next
 Next

最后的代碼幾乎沒有錯誤。

如果“狀態”單元格具有單個狀態,而相鄰的“城市”單元格具有值“全部”:它將正確驗證它。

但; 如果“狀態”單元格具有以分號分隔的多個狀態; 並且相鄰的“城市”單元格的值為“全部”,則代碼無法正確驗證它。

誰能幫助我我錯了? 以及如何提高代碼的性能...

查看您的代碼,看來您正在使它真的變得非常復雜,而實際上並不一定要這樣做。

如果我正確收集了這些信息,則用戶將在excelworkbook中輸入數據,並且您要確保他們遵循某些規則正確地執行了操作。 如果他們違反了規則,您將單元格塗成紅色。

更簡單,更快捷的方法是使用Excel內置的條件格式。 這也將允許您拆分代碼,並且僅檢查實際已更改的數據:因此無需遍歷所有單元格。

快速示例:

  • 如果在狀態下列出了多個狀態; 那么City的相鄰單元格應該(強制)僅具有值“ All”。 (就像列出了多個狀態一樣,上面的代碼無法正確驗證層次結構)您聲明多個狀態將用冒號分隔。 因此,您需要一條規則指出:如果B列下的單元格包含“;” 那么我在B列下的單元格必須包含“全部”。 如果不是這樣,我想將C列下的單元格塗成紅色。

要添加此規則,請選擇C列的第一個單元格,然后從Excel功能區的“主頁”選項卡中選擇“條件格式”。 然后,您創建一個新規則,並選擇使用公式來確定要格式化的單元格。 您需要的公式是“ = NOT(ISERROR(FIND(“;”; B1)))”然后將格式設置為紅色填充並保存規則。

現在,此規則將適用於第一行,為了使其適用於整個列,您可以去管理規則並將“適用於”字段調整為$ C:$ C,也可以將格式復制到單元格中您要使用。

您可以為工作簿上的每個規則創建條件格式設置規則。 您還可以為無法在Excel的本機功能中輕松表達的特定規則編寫函數代碼。

這將使您的檢查變得簡單且易於維護,但也將使您的用戶反饋迅速:一旦輸入值,規則就會被應用。

首先,讓我指出,我先前的答案中的方法可以輕松地應用於包含數據的工作簿,並且是最好的方法。

但是,當您要求輸入代碼時,也許您應該看一下其他代碼的第二部分。 如果州有多個州,並且可以在“管轄區”選項卡上找到州,則您的代碼將轉到以下else塊:

strFndAddress = rngFnder.Address
Do
    If c.Offset(, -2) = rngFnder.Offset(, -2) Then
        strFndAddress = ""
        c.Interior.Color = vbWhite
        Exit Do
    Else
        Set rngFnder = Sheets("Jurisdictions").Range("C2:C" & nLastRowSheet2).FindNext(rngFnder)
    End If
Loop While Not rngFnder Is Nothing And rngFnder.Address <> strFndAddress

該塊對“ All”值不執行任何操作。

另外,這一行使我感到困惑(不止一次):

c.Interior.Color = c.Interior.Color

您可能會喜歡的其他技巧:

  • 重命名變量,以便您可以實際讀取它們代表的含義:“ cityName”代替“ e”,cityCell代替“ c”產生很大的不同。
  • 使用工作表的UsedRange確定最后一行。 它比使用End函數更快,更穩定。
  • 不要使用On Error Resume Next。 這將掩蓋所有錯誤,並且很難發現發生的任何錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM