【问题标题】:Convert an array of bytes into a string?将字节数组转换为字符串?
【发布时间】:2018-10-31 02:52:08
【问题描述】:

我有整数数组,每个都是一个 ASCII 码,代表一个字符串的一个字节。

我可以像这样从数组中生成一个字符串:

Sub BytesToString()

    Dim myArr(): myArr = Array(84, 104, 105, 115, 32, _
        105, 115, 32, 97, 32, 116, 101, 115, 116, 33)

    Dim c As Variant, myStr As String

    For Each c In myArr
        myStr = myStr & Chr(c)
    Next c

    MsgBox myStr

End Sub

...但我觉得这不是“正确的方式”,尤其是因为可能需要重复转换。数组长度会有所不同。

有没有内置或更有效的方法用VBA生成字符串?

【问题讨论】:

  • 没有处理 ASCII 的内置工具。从概念上讲,将字符代码转换为 VBA 支持并且在您的数据范围内兼容的编码是合理的。 VBA 使用 UTF-16 字符串,因此使用 ChrW() 进行转换是一个明显的选择。 Chr() 也将是兼容的,但增加了以下方面:1) 用于使用用户的默认编码进行读取;2) 在 Chr() 返回其结果之前必须将其转换为 UTF-16。

标签: arrays excel vba byte ascii


【解决方案1】:

事实证明,这是解决方案如此简单以至于被包括我自己在内的几个人忽视的罕见情况之一。


? "Byte Arrays"Strings 基本上可以互换。

在 VBA 中,字节数组是特殊的,因为与其他数据类型的数组不同,字符串可以直接分配给字节数组。

在 VBA 中,字符串是 UNICODE 字符串,因此当将字符串分配给字节数组时,它会为每个字符存储两个数字。第一个数字是字符的 ASCII 值,下一个数字是 0。
(来源:VBA Trick of the Week: VBA 中的字节数组 - 有用的Gyaan)

几个代码示例可能比我能解释的更好:

Sub Demo1()
    Dim myArr() As Byte, myStr As String
    myStr = "Hi!"
    myArr() = myStr

    Debug.Print "myStr length: " & Len(myStr)                       'returns "3"
    Debug.Print "Arr bounds: " & LBound(myArr) &"to"& UBound(myArr) 'returns "0 to 5"
    myStr = myArr
    Debug.Print myStr                                               'returns "Hi!"
End Sub

在上述情况下,字符串的长度为 3,因此数组的大小为 6。值将以下列方式存储:

myArr(0) = 72 ' ASCII : code for 'H'
myArr(1) = 0 ' ASCII 'null' character
myArr(2) = 105 ' ASCII : code for 'i'
myArr(3) = 0 ' ASCII 'null' character
...etc...

如果想删除这些零,可以使用StrConv 函数。在这种情况下,它将只存储 ASCII 值。

    myByteArr() = StrConv("StackOverflow", vbFromUnicode)

就像字符串可以直接赋值给字节数组一样,字节数组也可以直接赋值给字符串。在上面的示例中,如果将myArr 分配给一个字符串,那么它将存储已分配给数组的相同值。

当数组是逐个元素填充的 - 或者,在我的例子中,来自快速文件操作(见下文) - 需要使用StrConv 进行额外的转换步骤。

Sub Demo2()
    Dim myArr(0 To 5) As Byte, myStr As String
    myArr(0) = 104: myArr(1) = 101: myArr(2) = 108
    myArr(3) = 108: myArr(4) = 111: myArr(5) = 33

    Debug.Print "myArr bounds: " & LBound(myArr) &"to"& UBound(myArr) 'returns "0 to 5"

    'since the array was loaded byte-by-byte, we can't "just put back":
    myStr = myArr()
    Debug.Print myStr                               'returns "???" (unprintable characters)
    Debug.Print "myStr length: " & Len(myStr)       'returns "3"

    'using `StrConv` to allow for 2-byte unicode character storage
    myStr = StrConv(myArr(), vbUnicode)
    Debug.Print myStr                                'returns "hello!"
    Debug.Print "myStr length: " & Len(myStr)        'returns "6"
End Sub

字节数组如何让我的一天变得更好......

我有大型文本文件,我一直想用 VBA 解析/分析,但找不到在加载或逐个字符解析方面不会非常缓慢的方法。

例如,今天我设法在 1/10th 秒内加载了一个 1/4 GB 的文件,并对其进行了解析成一个字节数组:

Dim bytes() As Byte
Open myFileName For Binary Access Read As #1
ReDim bytes(LOF(1) - 1&)
Get #1, , bytes
Close #1

For x = LBound(arrOut) To UBound(arrOut)
    Select Case bytes(x)

        (..and if I want the character)
            bytes2(y) = bytes(x)
            y = y + 1
    End Select
Next x
ReDim Preserve bytes2(LBound(bytes2) To y - 1)
txtIn = StrConv(bytes2, vbUnicode)

...我在 不到 5 秒 内完成了我的完整字符串。 (万岁!)


更多信息:

【讨论】:

    【解决方案2】:

    如果您对不同的方式感到好奇,您总是可以依靠 .NET 库!在这种情况下,您必须在 VBA 编辑器中添加对 mscorlib.dll 的引用,然后使用以下代码:

    Option Explicit
    Sub BytesToString()
        Dim en As ASCIIEncoding
        Set en = New ASCIIEncoding
    
        Dim myArr(0 To 2) As Byte
        myArr(0) = 72
        myArr(1) = 105
        myArr(2) = 33
    
        MsgBox en.GetString(myArr)
    End Sub
    

    既然您正在寻找 内置 功能,那就是其中之一。但它效率低下。我检查过的时间大约是您的自定义解码器的 10 倍。

    更新

    但是,当我在 .NET (C#) 中检查时,它比 OP 提供的自定义方法快大约 20 倍。

    【讨论】:

    • 然而,有效的例子,我不会称之为内置的。对于 .NET 当然是,但不是 VBA。我想知道,您是否在 .NET 中对其进行了测试?需要那么长时间吗?
    • @MichałTurczyn 我很伤心 - 我想要接受你的回答,因为你付出了所有努力,包括测试,并向我介绍了一个我不知道的 VB 函数的......但我想最重要的是它比我目前使用的方法效率低。我们将看到其他答案必须提供什么。 :)
    • @ashleedawg 我自己并不知道。我只知道,必须有一些图书馆提供这种方法。发现ASCIIEncoding 位于mscorlib,然后查找方法签名,知道要传递什么作为参数,就是这样:)
    【解决方案3】:

    串联是这段代码中昂贵的部分。这是您可以使用Join 处理的事情。我不确定这是 正确 的做法,但至少它更快:

    For i = LBound(myArr) To UBound(myArr)
        myArr(i) = Chr(myArr(i))
    Next
    MsgBox Join(myArr, "")
    

    【讨论】:

      猜你喜欢
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多