Является ли строка массивом в VBA, с которой можно выполнить итерацию?

Является ли строка массивом в VBA?

Например, можно ли перебирать его, как я мог, в C/С++?

Сделайте что-то вроде этого:

char myArray[10]; 

for (int i = 0; i < length; i++)
{
    cout << myArray[i];
}

Каким будет эквивалент в VBA? Он не ведет себя так, как я ожидал. Никогда в действительности не пытались манипулировать многими строками раньше в VBA!:)

Ответы

Ответ 1

Это не массив, но то, что вы хотите, можно сделать с помощью MID

Sub test()
    Dim strSentence As String
    Dim lngCount As Long    

    strSentence = "This is a string"

    For lngCount = 1 To Len(strSentence)
        Debug.Print Mid(strSentence, lngCount, 1)
    Next lngCount             
End Sub

См. также ответ Мат. чата для дополнительной хорошей точки.

Изменить

На самом деле существует второй способ итерации по строке, которая заключается в том, чтобы преобразовать строку в массив одноразрядных строк, а затем повторить их. Для этого нам нужно преобразовать исходную строку в формат unicode, чтобы символ Null можно было использовать как разделитель. Вот пример воспроизводимости:

Sub test2()
    Dim strSentence As String
    Dim lngCount As Long
    Dim strArray() As String

    strSentence = "This is a string"
    strSentence = StrConv(strSentence, vbUnicode)

    strArray = Split(strSentence, vbNullChar)

    For lngCount = 0 To UBound(strArray)
        Debug.Print strArray(lngCount)
    Next lngCount
End Sub

Из любопытства я сравнил два подхода (используя версию Mat версии Mid, которая быстрее):

Sub test_sub()
    Dim strTest(1 To 5000) As String
    Dim lngStringIter As Long
    Dim lngChars As Long, dblTick As Double

    ' Generate  some long strings first
    For lngStringIter = 1 To 5000
        strTest(lngStringIter) = vbNullChar
        For lngChars = 1 To 10
            strTest(lngStringIter) = strTest(lngStringIter) & _
                Chr(Int((90 - 65 + 1) * Rnd + 65)) & strTest(lngStringIter)
        Next lngChars
    Next lngStringIter

    ' Lets see what happens..
    dblTick = CDbl(Now())
    For lngStringIter = 1 To 5000
      test strTest(lngStringIter)
    Next lngStringIter
    Debug.Print "Time Mid: ", CDbl(Now()) - dblTick

    dblTick = CDbl(Now())
    For lngStringIter = 1 To 5000
      test2 strTest(lngStringIter)
    Next lngStringIter
    Debug.Print "Time Split: ", CDbl(Now()) - dblTick
End Sub

Результаты:

Time Mid:     4.62962998426519e-05 
Time Split:    1.15740767796524e-05 

Итак, кажется, что подход Split несколько быстрее.


Строка VBA реализована как тип данных BSTR. Более подробную информацию по этому типу данных можно найти здесь и здесь,

Ответ 2

Строка - это массив байтов, и вы можете перебирать ее, если знаете свой путь вокруг двухбайтовых реализаций строки (или Unicode, который обычно составляет 2 байта на символ, но может быть больше: и всегда будет 2 байта, если ваша строка возникла в VBA).

Когда я говорю , я имею в виду: нет необходимости в преобразовании типа, и это будет работать нормально:

Public Sub TestByteString()

    Dim strChars As String
    Dim arrBytes() As Byte
    Dim i As Integer


    strChars = "The quick Brown Fox"
    arrBytes = strChars

    Debug.Print strChars
    Debug.Print

    For i = LBound(arrBytes) To UBound(arrBytes) Step 2 

        Debug.Print Chr(arrBytes(i)) & vbTab & "Byte " & i & " = " & arrBytes(i)

    Next i

    arrBytes(0) = Asc("?")
    arrBytes(2) = Asc("!")
    arrBytes(4) = Asc("*")

    strChars = arrBytes

    Debug.Print
    Debug.Print strChars

    Erase arrBytes

End Sub

Ваши выходы будут выглядеть так:

Быстрая Браун Фокс

T Байт 0 = 84 h Байт 2 = 104 e Байт 4 = 101   Байт 6 = 32 q Байт 8 = 113 u Байт 10 = 117 i Байт 12 = 105 c Байт 14 = 99 k Байт 16 = 107   Байт 18 = 32 B Байт 20 = 66 r Байт 22 = 114 o Байт 24 = 111 w Байт 26 = 119 n Байт 28 = 110   Байт 30 = 32 F Байт 32 = 70 o Байт 34 = 111 x Байт 36 = 120

?! * quick Brown Fox

Обратите внимание на "Шаг 2" в цикле: я отбрасываю каждый другой байт, потому что знаю, что это простые ванильные латинские символы - текст "ASCII" для непосвященных.

Интересно, когда вам приходится иметь дело с текстом на арабском и пиньинь: и вы никогда не должны предполагать на листе реального мира, что вы всегда будете иметь дело с простым американским ASCII, как я это делал в этой демонстрации шт.

Для более подробного примера, с более подробным объяснением, попробуйте это у Excellerando:

Написание диапазона Excel для файл csv: оптимизация и совместимость с unicode

Оптимизация байтового массива находится в нижней части под этим заголовком:

Реализация VBA контрольной суммы Adler-32, работающая на байтовых массивах вместо использования обработки строк VBA.

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

Ответ 3

Mid работает, чтобы получить символ n th в любой строке, но возвращает Variant, что приводит к неявному преобразованию в String.

Используйте "строго типизированную" версию: Mid$.

Ответ 4

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

Однако вы можете использовать MID для получения одного символа за раз.

Код OTTOMH

declare i as integer
declare strlen as int

strlen = Len (YourIncomingString)

for i = 0 to strlen
    print Mid (YourIncomingString, i, 1)

Ответ 5

Простой ответ: нет, строка не является объектом в VBA. Вы должны были бы выделить его на персонаже в то время, используя функции mid и len.

Ответ 6

По-прежнему можно создать собственную пользовательскую перечислимую строку.

Перечислимая строка может быть использована следующим образом:

Dim es As EnumerableString
Set es = New EnumerableString
es.Value = ActiveCell.Value
Dim ch As Variant
For Each ch In es
    ActiveCell.Offset(1, 0).Activate
    ActiveCell.Value = ch
Next ch

Сохраните этот код в файле с именем EnumerableString.cls и импортируйте его в проект VBA.

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "EnumerableString"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

Private m_characters As Collection

Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
    Set NewEnum = m_characters.[_NewEnum]
End Property

Public Property Let Value(ByVal newValue As String)
    Dim pos As Integer
    Set m_characters = New Collection
    For pos = 1 To Len(newValue)
        m_characters.Add Mid$(newValue, pos, 1)
    Next pos
End Property

Public Function Length() As Long
    Length = m_characters.Count
End Function

Public Function Item(ByVal index As Variant) As String
Attribute Item.VB_UserMemId = 0
    Item = m_characters(index)
End Function

Private Sub Class_Initialize()
    Set m_characters = New Collection
End Sub

Результат в Excel, пример с символами ASCII, ANSI и Unicode UTF-8:

введите описание изображения здесь