Преобразовать массив байтов в строку? - PullRequest
0 голосов
/ 21 мая 2018

У меня есть массивы целых чисел, каждый из которых представляет собой код 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?

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

Если вам интересны разные способы, вы всегда можете рассчитывать на библиотеки .NET!В этом случае вам необходимо добавить ссылку на mscorlib.dll в вашем редакторе VBA, а затем использовать этот код:

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 #), это примерно в 20 разбыстрее, чем индивидуальный подход, представленный OP.

0 голосов
/ 09 июля 2018

Оказывается, это один из тех редких случаев, когда решение было настолько простым, что его игнорировали несколько человек, включая меня.


? "Байтовые массивы" и Строки в основном взаимозаменяемы.

В VBA байтовые массивы являются особыми, потому что, в отличие от массивовдругие типы данных, строка может быть непосредственно назначена байтовому массиву.

В VBA строки - это строки UNICODE , поэтому при назначении строки байтумассив затем хранит две цифры для каждого символа.Первая цифра будет ASCII значением символа, а следующая будет 0.
(Источник: VBA Trick of 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

Как Byte Array сделал мой деньнемного лучше ...

У меня есть большие текстовые файлы, которые я хотел проанализировать / проанализировать с помощью VBA, но не смог найти метод, который не был бы мучительно медленным ни при загрузке, ни при посимвольномРазбор символов.

Например, сегодня мне удалось загрузить файл размером в четверть гигабайта за 1 / 10 th секунды,и проанализировал его в второй массив байтов:

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 секунд всего. (Ура!)


Дополнительная информация:

0 голосов
/ 21 мая 2018

Конкатенация является дорогой частью этого кода.Это то, с чем вы можете справиться Join.Я не уверен, что это правильный способ сделать это, но это как минимум быстрее:

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