Является ли строка массивом в 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:
![введите описание изображения здесь]()