Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.71/21: Рейтинг темы: голосов - 21, средняя оценка - 4.71
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1

Правильная конкатенация

18.04.2023, 02:34. Показов 5675. Ответов 117
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
На другом форуме видел такой вариант конкатенации большого массива и он мне очень понравился, поскольку скорость близкая к join. На сколько я знаю тип String это структура содержащая в себе массив символов и еслиб у нас был доступ к этому массиву и возможность делать что-то вроде redim preserve.. В общем, можно ли как-то улучшить алгоритм, чтоб закасматить окончательно етот join? )
25.02.2012 08:28:33
Если правильно делать конкатенацию в цикле, то Join отдыхает:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
' Правильная конкатенация в цикле  
Sub FastConcat()  
 Dim x, t!, i&, j&, s$, v$  
 With Range("A1:Z65536")  'For i = 1 To 1703936: arr(i) = 1: Next
   .Value = 1  
   t = Timer  
   s = " "  
   For Each x In .Value  
     v = x & ";"  
     j = i + Len(v)  
     If j > Len(s) Then s = s & Space$(Len(s))  
     Mid$(s, i + 1) = v  
     i = j  
   Next  
   s = Left$(s, j - 1)  
   Debug.Print Timer - t  
 End With  
End Sub  
 
' Вариант с Join  
Sub io()  
 Dim t As Single  
 Dim x, z(), i As Long, line As String  
 With [A1:Z65536]
   .Value = 1  
   t = Timer  
   ReDim z(1 To .Cells.Count)  
   For Each x In .Value  
     i = i + 1  
     z(i) = x  
   Next  
   line = Join(z, ";")  
   Debug.Print Timer - t  
 End With  
End Sub
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.04.2023, 02:34
Ответы с готовыми решениями:

Из символов одного текста строковых функций о операций конкатенация получить другой текст
Из символов одного текста с помощью строковых функций о операций конкатенация получить другой текст. Из «информатика» получить «форма»...

Правильная обработка ошибок
Здравствуйте. У меня такой вопрос. Программа сама записывает файл по сети. Если сеть выключенна то на том компьюторре на котором работает,...

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

117
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
12.09.2023, 17:09
Студворк — интернет-сервис помощи студентам
testuser2, я рад, что у тебя всё получилось)))
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
12.09.2023, 17:50  [ТС]
Цитата Сообщение от testuser2 Посмотреть сообщение
Также видна работа команды redim preserve, то, что при увеличении массива можно по прежнему использовать тот же указатель.
Структура то на месте, а вот данные массива, судя по всему перезаписываются, поскольку указатели на элементы массива меняются после redim preserve..
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
12.09.2023, 20:02
Лучший ответ Сообщение было отмечено testuser2 как решение

Решение

Работать непосредственно с символами можно без проблем замапив SAFEARRAY дескриптор на данные:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Option Explicit
 
Private Const FADF_AUTO  As Long = 1
 
Private Type SAFEARRAYBOUND
    cCount              As Long
    lBound              As Long
End Type
Private Type SAFEARRAY1D
    cDims               As Integer
    fFeatures           As Integer
    cbElements          As Long
    cLocks              As Long
    pvData              As Long
    Bounds              As SAFEARRAYBOUND
End Type
 
Private Declare Sub PutMem4 Lib "msvbvm60" ( _
                    ByRef pAddr As Any, _
                    ByVal pVal As Long)
Private Declare Function ArrPtr Lib "msvbvm60" _
                         Alias "VarPtr" ( _
                         ByRef ppSA() As Any) As Long
                         
Private Sub Form_Load()
    Dim sString As String
    Dim tSADesc As SAFEARRAY1D
    Dim iText() As Integer
    Dim lIndex  As Long
    
    sString = "Hello"
    
    With tSADesc
        .cDims = 1
        .cbElements = 2
        .fFeatures = FADF_AUTO
        .pvData = StrPtr(sString)
        .Bounds.cCount = Len(sString)
    End With
    
    PutMem4 ByVal ArrPtr(iText), VarPtr(tSADesc)
    
    For lIndex = 0 To UBound(iText)
        iText(lIndex) = iText(lIndex) Xor &H20
    Next
    
    Debug.Print sString
    
End Sub
1
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
13.09.2023, 02:34  [ТС]
The trick, Спасибо за более подробный разбор структуры SafeArray, но еще можно добавить, что надо всегда запоминать прежние указатели, и возвращать потом их на место (для vba это критичный момент)

Добавлено через 13 минут
Цитата Сообщение от The trick Посмотреть сообщение
PutMem4 ByVal ArrPtr(iText), VarPtr(tSADesc)
Это момент еще бы надо как-то осмыслить. Если в одном случае (в товоей статье про указатели) для получения указателя испльзовалась отдельная процедура GetSa, то здесь как то просто, ArrPtr..
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
13.09.2023, 14:22  [ТС]
Все, понял как это работает, благодаря коду Анатолия. Получается, что VarPtr(ArrPtr) в случае с массивом дает нам адрес, места где находится указатель на структуру (SAFEARRAY1D). Поменяв этот указатель, мы легко можем залинковать переменнюу массива на свою структуру (как в данном случае), или на структуру другого массива, фактичеки сделав указатель-клон другого массива, который не будет сбиваться, даже если сделать redim preserve. На vba так будет рабоать без вылета, нужно только вернуть прежнее состояние массива (обнулить указатель) в конце.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Private Sub Form_Load3()
    Dim sString As String
    Dim tSADesc As SAFEARRAY1D
    Dim iText() As Integer
    Dim lIndex  As Long
    
    sString = "Hello Words"
    
    With tSADesc
        .cDims = 1
        .cbElements = 2
        .fFeatures = FADF_AUTO
        .pvData = StrPtr(sString)
        .Bounds.cCount = Len(sString)
    End With
    
'    PutMem4 ByVal ArrPtr(iText), VarPtr(tSADesc)
    CopyMemory ByVal ArrPtr(iText), VarPtr(tSADesc), 4    ' меняем указатель массива iText() на адрес структуры tSADesc
    
    For lIndex = 0 To UBound(iText)
        iText(lIndex) = iText(lIndex) Xor &H20
    Next
    
    Debug.Print sString
    
'    PutMem4 ByVal ArrPtr(iText), 0&
    CopyMemory ByVal ArrPtr(iText), 0&, 4                  ' восстанавливаем прежний указатель массива iText (0 - непроинициализированый)    
End Sub
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
13.09.2023, 16:07
testuser2, нифигасебе ты заморочился)
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
13.09.2023, 17:48  [ТС]
HackerVlad, еще бы с устройтвом 2мерного массива разобраться (в Екселе 2 мерные часто используются), и можеть сделать, какой-нибудь join для 2мерного массива..

Добавлено через 1 час 17 минут
x64 vba-совместимый вариант
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Private Declare PtrSafe Function ArrPtr Lib "VBE7" Alias "VarPtr" (Src() As Any) As LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
 
Private Type SAFEARRAYBOUND
    cCount              As Long
    lBound              As Long
End Type
Private Type SAFEARRAY1D
    cDims               As Integer
    fFeatures           As Integer
    cbElements          As Long
    cLocks              As Long
    pvData              As LongPtr
    Bounds              As SAFEARRAYBOUND
End Type
Private Const FADF_AUTO  As Long = 1
 
Private Sub Form_Load3()
    Dim sString As String
    Dim tSADesc As SAFEARRAY1D
    Dim iText() As Integer
    Dim lIndex  As Long
    Dim lnull As LongPtr
    
    sString = "Hello Words x64 Compatible"
    
    With tSADesc
        .cDims = 1
        .cbElements = 2
        .fFeatures = FADF_AUTO
        .pvData = StrPtr(sString)
        .Bounds.cCount = Len(sString)
    End With
    
    CopyMemory ByVal ArrPtr(iText), VarPtr(tSADesc), Len(lnull)    ' меняем указатель массива iText() на адрес структуры tSADesc
    
    For lIndex = 0 To UBound(iText)
        iText(lIndex) = iText(lIndex) Xor &H20
    Next
    
    Debug.Print sString
    
    CopyMemory ByVal ArrPtr(iText), lnull, Len(lnull)              ' восстанавливаем прежний указатель массива iText (0 - непроинициализированый)
 
End Sub
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
13.09.2023, 19:33
Цитата Сообщение от testuser2 Посмотреть сообщение
и можеть сделать, какой-нибудь join для 2мерного массива..
а мне это зачем? я не умею делать join и для простого массива даже))) ни разу небыло нужно вообще

Добавлено через 59 секунд
да и вместо двухмерного массива мне проще массив структуры использовать) с нужными атрибутами)))
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
13.09.2023, 20:17
Цитата Сообщение от testuser2 Посмотреть сообщение
что надо всегда запоминать прежние указатели, и возвращать потом их на место
По идеи тут не нужно, т.к. установлен флаг FADF_AUTO.

Цитата Сообщение от testuser2 Посмотреть сообщение
Это момент еще бы надо как-то осмыслить. Если в одном случае (в товоей статье про указатели) для получения указателя испльзовалась отдельная процедура GetSa, то здесь как то просто, ArrPtr..
Да ArrPtr возвращает указатель на переменную которая содержит дескриптор массива. Нужно уточнить что для массива String или UDT содержащей String нужно использовать отдельное объявление.
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
14.09.2023, 18:06  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
По идеи тут не нужно, т.к. установлен флаг FADF_AUTO.
В vba, как я понял, указатели возвращать нужно везде, кроме, тех, которые меняются в стеке.
С SafeArray разных размерностей и типов, более менее освоился. У всех массивов данные в сущности являются единым блоком, который можно представить как вектор (1d массив). Если это матрица, то элементы располагаются постолбечно.
Прямой доступ к данным вариантного 2мерного массива:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Private Type sVariant
    c As Currency
    s As String
    l As Long
End Type
 
Sub fsf() 
    Dim arr1() As sVariant, arr2()
    Dim tSADesc As SAFEARRAY1D
    
    ReDim arr2(2, 0)
    arr2(0, 0) = "ппвпппып"
    arr2(2, 0) = "ffffafaf"
    
    With tSADesc
        .cDims = 1
        .cbElements = 16
        .fFeatures = FADF_AUTO
        .pvData = VarPtr(arr2(0, 0))
        .Bounds.cCount = UBound(arr2) + 1 '- LBound(arr2)
    End With
    CopyMemory ByVal ArrPtr(arr1), VarPtr(tSADesc), 4
    
    Debug.Print arr1(0).s; vbCr; arr1(2).s
    
    CopyMemory ByVal ArrPtr(arr1), 0&, 4      
End Sub
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
16.09.2023, 04:50  [ТС]
Цитата Сообщение от HackerVlad Посмотреть сообщение
а мне это зачем? я не умею делать join и для простого массива даже))) ни разу небыло нужно вообще
Дело може быть не в joinе как таковом, а в лучшем понимании, как правильней работать с памятью. Ведь правильней же лучше?
Вот, к слову, интересная страничка, пока не уловил, в чем там суть. Кто поймет объясните в общих чертах если не трудно.
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.09.2023, 12:13
Цитата Сообщение от testuser2 Посмотреть сообщение
пока не уловил, в чем там суть
я тоже если честно не понял, зачем было писать GetMem функции на основе CopyMemory тупость какая-то
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
16.09.2023, 13:01  [ТС]
У меня по его тестам, api функция, оказалась значительно быстрее, чем его реализация, но кто его знает, может было бы по другому, на x64 c последними обновлениями и включенным "защитником". У него без CopyMemory как-то работает, почему-то используется variant..
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.09.2023, 14:27
testuser2, да не обращай внимания на этот код вообще
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
16.09.2023, 14:30
testuser2, любая API функция объявленная так будет тормозить на любых данных где есть строки.
0
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
16.09.2023, 15:17  [ТС]
Цитата Сообщение от HackerVlad Посмотреть сообщение
не обращай внимания
Может быть, но все же, хотелось бы сказать пару слов. Во-первых спасибо человеку, за проделаную работу, код довольно не простой, там есть мысль. Если код хороший - отлично, если код не очень хороший, тоже не плохо, значит есть повод сказать, что-нибудь умное (или подумать) ). Немного поразбираем , что там происходит. 1 тест: для копирования 1 байта (в длинном цикле) у него во первых происходит 2 раза вызов VarPtr, возвращающую Long (4 байта, уже хорошо )), далее эти 4 байта передаются, по значению, в MemByte, то беж копируются в стек.
Visual Basic
1
VarPtr, MemByte(VarPtr(x1)) = MemByte(VarPtr(x2))
Visual Basic
1
2
3
Public Property Get MemByte(ByVal memAddress As LongPtr) As Byte   
        RemoteAssign rm, memAddress, rm.remoteVT, vbByte + VT_BYREF, MemByte, rm.memValue    
End Property
Внутри MemByte "выстреливает" процедура с аж 6 аргументами, 3 из которых Varint, 1 структура с двумя "вариантами" но все это передается по ссылке (по 4 байта), один аргумент по значению, но также имеет размер 4 байта. 6*4 = 24 байта - размер стека. Внутри этой функции происходит 2 4байтных присвоения (то беж копирования), и 2 вариантных.. При том этот RemoteAssign каждый раз по 4 раза долбает.. В общем все это кучерявинько как то.. )
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Private Sub RemoteAssign(ByRef rm As REMOTE_MEMORY _
                       , ByRef memAddress As LongPtr _
                       , ByRef remoteVT As Variant _
                       , ByVal newVT As VbVarType _
                       , ByRef targetVariable As Variant _
                       , ByRef newValue As Variant)
    rm.memValue = memAddress
    If Not rm.isInitialized Then InitRemoteMemory rm
    remoteVT = newVT
    targetVariable = newValue
    remoteVT = vbEmpty 'Stop linking to remote address, for safety
End Sub
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
16.09.2023, 15:22
Такое вообще проще сделать через SAFEARRAY. Сделать Long массив размером от 0 до 536870912 и адресовать всю память. Для Byte и Integer просто битовыми масками выделять нужную часть. Для 64 бит так уже не получится придется динамически подгонять размер или указатель т.к. там 64 битная адресация.
1
1386 / 842 / 91
Регистрация: 08.02.2017
Сообщений: 3,585
Записей в блоге: 1
16.09.2023, 15:59  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Сделать Long массив размером от 0 до 536870912 и адресовать всю память.
Не совсем понял о чем речь. Ну то есть знаю, что можно на блок данных массива сослать что угодно и сам массив можно сослать на что угодно. Какие сложности могут быть с 64бит?, знаю, только, что там размер указателя 8 байт и если нужно сделать массив указателей, то выбрать тип LongPtr или LongLong для массива.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
16.09.2023, 16:05
Цитата Сообщение от testuser2 Посмотреть сообщение
Не совсем понял о чем речь.
Все тоже самое что тут только .pvData = 0, а .Bounds.cCount = 536870912. Получается что можно адресовать всю память от 0 до 0x7fffffff с шагом 4 байта.

Цитата Сообщение от testuser2 Посмотреть сообщение
Какие сложности могут быть с 64бит?
В SAFEARRAYBOUND количество элементов тип ULONG, т.е. больше 4 байт туда нельзя записать. Соответственно максимальный адрес при 0м указателе который получится адресовать равен 0xFFFFFFFF * 4 = 0x3FFFFFFFC, однако размер адресного пространства гораздо больше - 63 бит.
1
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
16.09.2023, 16:07
Цитата Сообщение от The trick Посмотреть сообщение
63 бит
Первый раз слышу, я думал бывает только 64 бит)))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
16.09.2023, 16:07
Помогаю со студенческими работами здесь

конкатенация строк в excel через vba
Здравствуйте, столкнулся с проблемой. у меня есть 5 файлов excel с данными и один. куда надо вывести информацию, в одних и тех же ячейках...

Конкатенация и последующее копирование уникальных строк по условию
В файле есть 2 рабочих листа. Требуется с одного листа(List1), начиная с колонки С10, конкатенировать значения ячеек по строке до тех пор,...

Добавление записей массива из одной книги на лист другой + возможная конкатенация
Уважаемые форумчане! Возник вопрос касательно познания средств VBA в Excel'e. Идея такая: есть пользовательская форма, которую нужно...

Из символов одного текста с помощью стоковых функций о операция конкатенация получить другой текст
Из символов одного текста с помощью стоковых функций о операция конкатенация получить другой текст. Из "алгоритм " получить...

Конкатенация
Ребята как быть раньше было так : <img class="frame" src="<?php echo...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru