使用Left()作为变量

时间:2017-06-28 12:29:31

标签: vba

我是VBA的新手。 所以我试图将前缀附加到一组值,具体取决于每个值的第一个数字。 但是我在第4行遇到类型不匹配错误。我想这是因为我试图在一个变量上使用Left(),它应该用在一个字符串上(或者某种类似的东西?) 我如何实现这一目标?

提前谢谢

Sub test()
a = UsedRange.Rows.Count
Testvariable = Range("A1", "A" & a)
FirstNo = Left(Testvariable, 1)
For i= 1 To a
If FirstNo(i,1) = "1" Then
Cells(i,2) = "abc" & FirstNo(i,1)
Else Cells(i,2) = "def" & FirstNo(i,1)
End if
Next
End Sub

4 个答案:

答案 0 :(得分:3)

麻烦的是,当Range想要set left时,您正试图在string对象的左侧,在没有Sub test() dim a as long a = UsedRange.Rows.Count dim Testvariable as string Testvariable = RangeToString(Range("A1", "A" & a)) dim FirstNo as string FirstNo = Left(Testvariable, 1) dim i as long For i= 1 To a If FirstNo(i,1) = "1" Then Cells(i,2) = "abc" & FirstNo(i,1) Else Cells(i,2) = "def" & FirstNo(i,1) End if Next End Sub Function RangeToString(ByVal myRange as Range) as String RangeToString = "" If Not myRange Is Nothing Then Dim myCell as Range For Each myCell in myRange RangeToString = RangeToString & "," & myCell.Value Next myCell 'Remove extra comma RangeToString = Right(RangeToString, Len(RangeToString) - 1) End If End Function 关键字的情况下分配给您一个数组}。

这篇文章解释了如何将范围转换为字符串,然后可以传递给左边。 How can I convert a range to a string (VBA)?

a = UsedRange.Rows.Count

另外,请务必正确声明变量。

a表示创建一个名为variant的{​​{1}}类型的变量,并为其赋值UsedRange.Rows.Count

Testvariable = Range("A1", "A" & a)表示创建名为Testvariable的{​​{1}}类型的变量,并为其指定范围对象的variant(数组)

如果这些被正确宣布

.value

Testvariable的赋值将失败并出现更明显的错误,通知您无法将数组转换为字符串。

答案 1 :(得分:2)

Testvariable = Range("A1", "A" & a)

Testvariable是一个数组(除非a=1,这不是你的情况)

Left足够灵活,可以接受除字符串之外的数字,但不接受数组。

答案 2 :(得分:1)

如果我遵循你的流程,我认为这会让你得到你想要的东西。

Sub test()
    Dim ws As Worksheet
    Set ws = ActiveWorkbook.ActiveSheet
    a = ws.UsedRange.Rows.Count
    TestVariable = Range("A1", "A" & a)

    For i = 1 To a
        FirstNo = Left(TestVariable(i, 1), 1)

        If FirstNo = "1" Then
            Cells(i, 2) = "abc" & FirstNo(i, 1)
        Else
            Cells(i, 2) = "def" & FirstNo
        End If
    Next i
End Sub

我认为问题是,除了其他两个答案之外,你需要循环遍历细胞根据每个细胞值输出一些东西。因此,只需将代码放在for循环内部,然后根据需要进行更改。

答案 3 :(得分:1)

VBA在你背后做了很多事情,以“让事情变得更轻松”。问题是这些东西会回来后再咬你。

例如,

未声明的变量。如果在每个模块的顶部都没有指定Option Explicit,VBA将很乐意编译使用未声明的变量的代码。听起来有用吗?如果类型推断,那就是。但是相反,VBA声明了一个动态Variant,它保存你放入它的任何东西(并改变它的类型以容纳你指定的任何东西)。

a = UsedRange.Rows.Count

此处a是隐式Variant/Long。将其声明为Long整数:

Dim a As Long

更好的是,给它一个有意义的名字:

Dim usedRows As Long
usedRows = UsedRange.Rows.Count

现在有趣的部分:

Testvariable = Range("A1", "A" & a)

此处Testvariable是隐式Variant/Array。怎么会这样? VBA看到的代码如下所示:

Testvariable = Range("A1", "A" & a).Value

由于a不是1.Value指的是多个单个单元格 - Excel的对象模型会为您提供一个包含所有单元格值的数组指定的范围,这就是Testvariable包含的范围。

如果您希望Testvariable引用范围而不只是引用它们的值,您将声明一个Range对象变量,并为其分配Set } keyword:

Dim testVariable As Range
Set testVariable = ActiveSheet.Range("A1:A" & a)

注意这里的显式ActiveSheet:没有它,代码完全相同,所以为什么要把它放进去?因为您希望尽可能显式:不合格的RangeCellsRowsColumnsNames会隐式调用请参阅活动工作表 - 这是另一个错误来源(只是google up“范围错误1004”,你会发现数百个Stack Overflow问题)。

如果您希望testVariable包含指定范围内每个单元格的,那么您将声明并指定testVariable,如下所示:

Dim testVariable As Variant
testVariable = ActiveSheet.Range("A1:A" & a).Value

现在你有一个数组,其中包含活动工作表范围"A1:A" & a中的所有值:这就是你的代码所做的...隐式。

FirstNo = Left(Testvariable, 1)

所以现在我们想要“第一个数字”,我们正在从变量数组中读取它。

Left(或Left$)函数来自VBA.Strings模块,意味着使用字符串;它也可以与其他类型一起使用(使用隐式类型转换),但是如果你给它一个对象引用或一个数组,它将不知道如何为你转换它,并且VBA将引发一个运行时错误。

testVariable变量数组包含Variant个值:大多数单元格将包含Double个浮点值。其他人将包含String。某些单元格可能包含错误值(例如#N/A#VALUE!#REF!) - 并且VBA也无法隐式转换此类错误值。

因此,在您阅读任何单元格的值之前,您需要确保可以读取它;使用IsError函数:

If IsError(testVariable(1, 1)) Then
    Exit Sub ' cell contains an error; cannot process
If Not IsNumeric(testVariable(1, 1)) Then
    Exit Sub ' cell doesn't contain a number; cannot process
End If

' now that we KNOW our value is a numeric value...
Dim firstNumber As Double
firstNumber = testVariable(1, 1)

请注意(1, 1)?这是因为testVariable是一个基于1的2D数组(没有Option Base 1隐式大小的数组总是从0开始,除非你从Range获得一个数组,所以要阅读在第一行/第一列中的值,您需要读取索引(1, 1)处的值。

但那不是你想要做的。

  

所以我试图将前缀附加到一组值,具体取决于每个值的第一个数

“每个值”意味着你需要迭代这些值,所以你有一个循环。

Dim i As Long
For i = 1 To a
    '...
Next

这不是我们想要的“第一个数字”,而是我们循环的每个单元格的firstDigit

If FirstNo(i,1) = "1" Then

在这里,你已经忘记了你正在处理的类型:在循环开始之前,FirstNo被分配了,所以它的值在每次迭代时都是常量。

你的意思是这样做:

Dim values As Variant
values = ActiveSheet.Range("A1:A" & usedRows).Value

Dim i As Long
For i = 1 To usedRows
    If Not IsError(values(i)) Then

        Dim representation As String
        representation = CStr(values(i))

        Dim prefix As String
        If Left$(representation, 1) = "1" Then
            prefix = "abc"
        Else
            prefix = "def"
        End If

        ActiveSheet.Range("B" & i).Value = prefix & representation

    End If
Next

现在所有内容都是明确的并且正确缩进,更容易看到发生了什么......现在我要认真地质疑为什么你需要VBA来做到这一点:

[B1] = IFERROR(IF(LEFT(A1, 1) = "1", "abc" & A1, "def" & A1), "")

然后拖下公式。