首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >下标超出范围(在Excel中从多个逗号分隔字符串宏中提取子字符串)

下标超出范围(在Excel中从多个逗号分隔字符串宏中提取子字符串)
EN

Stack Overflow用户
提问于 2017-01-02 20:36:23
回答 2查看 395关注 0票数 0

我在Sheet1上有以下列表:

代码语言:javascript
运行
复制
   COLUMN A    COLUMNB                                                      COLUMN C 
1  ADDRESS     Services(s) USED                                             VEHICLE(S) USED
2  Address1    Service4                                                     Vehicle1, Vehicle3, Vehicle4  
3  Address1    Service3                                                     Vehicle1, Vehicle3, Vehicle4
4  Address2    Service5                                                     Vehicle1, Vehicle2, Vehicle5
5  Address2    Service2                                                     Vehicle1, Vehicle6 
6  Address2    Service1, Service2, Service3, Service4, Service5, Service6   Vehicle2, Vehicle5, Vehicle6 
7  Address1    Service1, Service2, Service3, Service4, Service5, Service6   Vehicle2, Vehicle3

在Sheet2上,当我在单元格B4中输入"Address1“时,我希望B列中的输出如下

代码语言:javascript
运行
复制
   COLUMN A    COLUMN B            


4              Address1                                                                 

12             Service1
13             Service2
14             Service3
15             Service4
16             Service5
17             Service6

50             Vehicle1
51             Vehicle2
52             Vehicle3
53             Vehicle4
54             Vehicle5
56             Vehicle6

Worksheet_Change代码 ("Sheet2“模块)

代码语言:javascript
运行
复制
Private Sub Worksheet_Change(ByVal Target As Range)

' call Function only if modifed cell is in Column "B"
If Not Intersect(Target, Range("B4")) Is Nothing Then
    Application.EnableEvents = False

    Call FilterAddress(Target.Value)
End If

Application.EnableEvents = True

End Sub

子FilterAddress代码(常规模块)

代码语言:javascript
运行
复制
Option Explicit

Sub FilterAddress(FilterVal As String)


Dim LastRow As Long
Dim FilterRng As Range, cell As Range
Dim Dict As Object
'Dim ID
Dim Vehicle As Variant
Dim VehicleArr As Variant
Dim i As Long, j As Long
Dim Service As Variant
Dim ServiceArr As Variant
Dim x As Long, y As Long
Dim My_Range As Range

With Sheets("Sheet1")
    ' find last row with data in column "A" (Adress)
    LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row

    Set FilterRng = .Range("A1:C" & LastRow)

    .Range("A1").AutoFilter
    ' AutoFilter "Sheet1" according to value in "Sheet2" in Column B
    FilterRng.AutoFilter Field:=1, Criteria1:=FilterVal

    Set Dict = CreateObject("Scripting.Dictionary")

    ' create an array with size up to number of rows >> will resize it later
    ReDim ServiceArr(1 To LastRow)
    j = 1 ' init array counter

    For Each cell In .Range("B2:B" & LastRow).SpecialCells(xlCellTypeVisible)
        ' read values from cell to array using the Split function
        Service = Split(cell.Value, ",")

        For i = LBound(Service) To UBound(Service)
            Service(i) = Trim(Service(i)) ' remove extra spaces from string

            If Not Dict.exists(Service(i)) Then
                Dict.Add Service(i), Service(i)

                ' save Service Name to array >> will use it later for "Bubble-sort" and paste in "Sheet2"
                ServiceArr(j) = Service(i)
                j = j + 1 ' increment ServiceArr counter
            End If
        Next i

    Next cell
    ' resize array up to number of actual Service
    ReDim Preserve ServiceArr(1 To j - 1)

End With

Dim ServiceTmp As Variant
' Bubble-sort Service Array >> sorts the Service array from smallest to largest
For i = 1 To UBound(ServiceArr) - 1
    For j = i + 1 To UBound(ServiceArr)
        If ServiceArr(j) < ServiceArr(i) Then
            ServiceTmp = ServiceArr(j)
            ServiceArr(j) = ServiceArr(i)
            ServiceArr(i) = ServiceTmp
        End If
    Next j
Next i

' now the "fun" part >> paste to "Sheet2"
With Sheets("Sheet2")
    .Range("A1").Value = "ADDRESS"
    .Range("B4").Value = FilterVal
    .Range("C1").Value = "VEHICLE(S) USED"

    ' clear contents from previous run

    .Range("B12:B17").ClearContents
    .Range("B12:B" & UBound(ServiceArr) + 11) = WorksheetFunction.Transpose(ServiceArr)

End With

FilterRng.Parent.AutoFilterMode = False

With Sheets("Sheet1")
    ' find last row with data in column "A" (Adress)
    LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row

    Set FilterRng = .Range("A1:C" & LastRow)

    .Range("A1").AutoFilter
    ' AutoFilter "Sheet1" according to value in "Sheet2" in Column B
    FilterRng.AutoFilter Field:=1, Criteria1:=FilterVal

    Set Dict = CreateObject("Scripting.Dictionary")

    ' create an array with size up to number of rows >> will resize it later
    ReDim VehicleArr(1 To LastRow)
    y = 1 ' init array counter

    For Each cell In .Range("C2:C" & LastRow).SpecialCells(xlCellTypeVisible)
        ' read values from cell to array using the Split function
        Vehicle = Split(cell.Value, ",")

        For x = LBound(Vehicle) To UBound(Vehicle)
            Vehicle(x) = Trim(Vehicle(x)) ' remove extra spaces from string

            If Not Dict.exists(Vehicle(x)) Then
                Dict.Add Vehicle(x), Vehicle(x)

                ' save Vehicle Name to array >> will use it later for "Bubble-sort" and paste in "Sheet2"
                VehicleArr(y) = Vehicle(x)
                y = y + 1 ' increment VehicleArr counter
            End If
        Next x

    Next cell
    ' resize array up to number of actual Vehicle
    ReDim Preserve VehicleArr(1 To y - 1)

End With

Dim VehicleTmp As Variant
' Bubble-sort Vehicle Array >> sorts the Vehicle array from smallest to largest
For x = 1 To UBound(VehicleArr) - 1
    For y = x + 1 To UBound(VehicleArr)
        If VehicleArr(y) < VehicleArr(x) Then
            VehicleTmp = VehicleArr(y)
            VehicleArr(y) = VehicleArr(x)
            VehicleArr(x) = VehicleTmp
        End If
    Next y
Next x

' now the "fun" part >> paste to "Sheet2"
With Sheets("Sheet2")
    .Range("A1").Value = "ADDRESS"
    .Range("B4").Value = FilterVal
    .Range("C1").Value = "VEHICLE(S) USED"

    ' clear contents from previous run

    .Range("B50:B55").ClearContents
    .Range("B50:B" & UBound(VehicleArr) + 49) = WorksheetFunction.Transpose(VehicleArr)

End With

FilterRng.Parent.AutoFilterMode = False
End Sub

当我在单元格Address1上输入“B4”时,会收到以下错误:

代码语言:javascript
运行
复制
Runtime error '9':

Subscript out of range

但是,如果我保存已填充B4的文件并关闭它,然后重新打开该文件,则在编辑单元格内容时,可以使宏正常工作,比如Address1或Address2。

是什么导致“子脚本超出范围”消息出现,我如何更改代码以避免它?是否需要更新Worksheet_Change Code中的代码?

我还注意到,如果删除Sheet2上的单元格Sheet2的内容,就会得到以下错误:

代码语言:javascript
运行
复制
Run-time error'1004':

No cells were found.

这两个错误是相关的吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-02 20:53:41

好吧,只是胡思乱想,但你能试试以下几点吗?

选项1

代替:

代码语言:javascript
运行
复制
For i = 1 To UBound(ServiceArr) - 1
    For j = i + 1 To UBound(ServiceArr)

写入:

代码语言:javascript
运行
复制
For i = 0 To UBound(ServiceArr) - 1
    For j = i + 1 To UBound(ServiceArr)

选项2

代替:

代码语言:javascript
运行
复制
j = 1 ' init array counter

写入:

代码语言:javascript
运行
复制
j = 0 ' init array counter

如果不起作用,请提供有关错误行的信息。一旦你看到错误信息,按下调试键,看看哪一行是黄色的。

票数 0
EN

Stack Overflow用户

发布于 2017-01-03 00:48:55

最大的'j‘不是由工作表上的行数来限制的--它是由可以从这些行中分割出来的元素数所限制的。在执行代码之前,无法确定ServiceArr需要的大小。这意味着根据数据,您将在本节中得到间歇性的下标错误:

ReDim ServiceArr(1 To LastRow)‘--这只是猜测。J=1适用于.Range("B2:B“& LastRow).SpecialCells(xlCellTypeVisible)服务= Split(cell.Value,",")表示I=LBound(服务)服务(I)=UBound(服务)服务(I)=Trim(服务(I))如果不是Dict.exists(服务(I)),则Dict.Add服务(I),Service(i) ServiceArr(j) = Service(i)‘<--如果唯一元素> LastRow j=j+1结束(如果下一个单元格为Next i),则这里出现子脚本错误

这个解决方案非常容易--完全摆脱ServiceArr。它将始终与Dict.KeysDict.Values完全相同,因为这里基本上保留了相同数据的第3份相同副本:

Dict.Add Service(i), Service(i) ServiceArr(j) = Service(i)

这与代码几乎完全相同,但它提供了一个基于0的数组,而不是基于1的数组:

代码语言:javascript
运行
复制
For Each cell In .Range("B2:B" & LastRow).SpecialCells(xlCellTypeVisible)
    Service = Split(cell.Value, ",")
    For i = LBound(Service) To UBound(Service)
        Service(i) = Trim(Service(i))
        If Not Dict.exists(Service(i)) Then
            Dict.Add Service(i), Empty
        End If
    Next i
Next cell

ServiceArr = Dict.Keys
'...
'Adjust this to 0 based.
For i = LBound(ServiceArr) To UBound(ServiceArr)

有关获得另一个错误的原因,请参见@YowE3K's comment

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41433000

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档