Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
Преобразовать строку в массив (VBA)
 
Hugo, Doober, Максим Зеленский, спасибо Вам за хорошие варианты решений! Решение Максима претендовало на окончательное... пока не появился С.М.

Это действительно круто. С.М.,  Вы предложили наикрутейшее решение!
Цитата
...
Arr = Evaluate(Replace(Mid(S, 2, Len(S) - 2), "},{", ";"))

Достойное пополнение в Золотую коллекцию фичей VBA! Ничего подобного нет в сети, включая MSDN.

Огромное Вам спасибо!
Изменено: Alex.Karev - 18.08.2016 22:50:30
Преобразовать строку в массив (VBA)
 
Всем доброго дня!
Прошу уважаемых форумчан помочь советом по следующей ситуации.

[VBA]: обрабатывается построчно текстовый файл большого размера (100+ Мб).
Каждая считанная строка имеет следующий вид (пример):
Код
{{"Василий","Инженер",55000,35},{"Михаил","Юрист",65000,42},{"Светлана","офис-менеджер",35000,27}}

Согласно синтаксису VB (не VBA), подобная запись информации (с использованием вложенных литералов `{` и `}` ) соответствует записи двумерного массива.
Цитата
' https://msdn.microsoft.com/ru-ru/library/wak0wfyt.aspx
...
Dim grid = {{1, 2}, {3, 4}}
...
А синтаксис описания массивов в VBA, к сожалению, иной и фигурные скобки не воспринимаются.

Требуется: присвоить содержимое вышеуказанной строки переменной, являющей двумерным массивом для последующей обработки строк и столбцов. К примеру - суммированию в цикле зарплат сотрудников, чей возраст менее 40 лет.

Проблема: описание массивов в VBA не воспринимает фигурные скобки. Можно было бы через RegExp привести строку к виду
Код
Array(Array("Василий","Инженер",55000,35),Array("Михаил","Юрист",65000,42),Array("Светлана","Офис-менеджер",35000,27))
и применить (бы) evaluate, но Evaluate в VBA обрабатывает только арифметические выражения...

Я пытался воспользоваться другим редактором:
Код
Dim d As New MSScriptControl.ScriptControl
d.Language = "VBScript"...
но он так же отличается от VB и не воспринимает синтаксис массива с применением фигурных скобок.

Уважаемые коллеги, подскажите, какие есть идеи или варианты на Ваш взгляд, кроме простого перебора строки и заполнения в цикле двумерного массива для приведения его к виду
Цитата
Василий      Инженер         55000    35
Михаил       Юрист           65000    42
Светлана     Офис-менеджер   35000    27
Скорость работы решения важна, поскольку файл - большого размера.

Заранее благодарю Вас за участие в обсуждении!
Изменено: Alex.Karev - 18.08.2016 10:39:52
Записать значение в ячейку Excel с помощью win api
 
Казанский, ещё раз БОЛЬШОЕ спасибо за подробные понятные комментарии и разъяснения!
Позвольте поделиться результатами предложенного Вами эксперимента.

Итак, речь шла о классе clsValueKeeper и его экземпляре myObj. В классе было объявлено Private поле (внутренняя переменная) v, не доступная напрямую при работе с экземплярами класса.

Справочно сообщу, что при поиске решения встретился пример (листинг 8.6) из учебника Джесса Либерти на С++, очень похожий на наш экспериментальный пример:
Код
 #include <iostream>
 
 #include <stdlib.h>
 
  class SimpleCat
  {
  public:код
   SimpleCat() {itsAge = 2;}
   ~SimpleCat() {}
  int GetAge() const {return itsAge;}
  void SetAge(int age) {itsAge = age;}
private:
  int itsAge;
 };
 
int main()
 {
 using namespace std;
  SimpleCat*Frisky=newSimpleCat;
  cout << "Frisky is " << Frisky->GetAge()
           << " years old" << endl;
  Frisky->SetAge(5);
  cout << "Frisky is " << Frisky->GetAge()
               << " years old" << endl;
  delete Frisky;
   return 0; 
}
Здесь в классе SimpleCat также объявлена private-переменная itsAge.

Теперь о решении. Для начала я немного усложнил исходное задание:
  • в классе я увеличил количество private-переменных (теперь это `v` и `w`) и изменил формулы их расчёта - теперь они не просто равны аргументу `x`, и свойство Value не просто равно значерию `v`. Сделано это было для наглядности, чтобы иметь возможность отличить, значение какой именно переменной мы найдём в обход нормального интерфейса - свойства Value.
Код
'модуль класса clsValueKeeper
 
Private v, w 'As Variant
 
Public Property Let Value(x As Variant)
  v = x * 2
  w = x * 5
End Property
 
Public Property Get Value()
  Value = v / 2
End Property
  • дополненный решением обычный модуль (обращаю внимание уважаемых читателей, что приведённое решение реализовано для win7/x64):
Код
'===============================
'обычный модуль

#If VBA7 Then
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Dst As Any, Src As Any, ByVal bytes As Long)
#Else
Private Declare Sub RtlMoveMemory Lib "kernel32" (Dst As Any, Src As Any, ByVal bytes As Long)
#End If

Sub test()

 Dim myObj As New clsValueKeeper ' инициирован (вызван) класс, в динамической памяти создан его экземпляр (myObj)
 Dim v As Long           ' сюда мы будем считывать из памяти значение внутренней переменной v
 Dim w As Long           ' сюда мы будем считывать из памяти значение внутренней переменной w
 Const offset_v = 104    ' смещение первой переменной класса в порядке их описания в модуле класса, байт
 Const offset_w = 128    ' смещение второй переменной класса в порядке их описания в модуле класса, байт

' Поехали!

 myObj.Value = 555  ' внутренним переменным класса - v и w - уже присвоены значения 1100 и 2775 (44Ch и AD7h)
 MsgBox myObj.Value ' 555

 RtlMoveMemory v, ByVal ObjPtr(myObj) + offset_v, 4& ' считали в переменную v её значение из памяти (4 байта)
 RtlMoveMemory w, ByVal ObjPtr(myObj) + offset_w, 4& ' считали в переменную w её значение из памяти (4 байта)

 Debug.Print "v = " & v  ' v = 1110
 Debug.Print "w = " & w  ' w = 2775

 ' теперь искусственно поменяем значение переменной v

 RtlMoveMemory ByVal ObjPtr(myObj) + offset_v, &H888, 8& ' теперь содержимое памяти, относящееся к переменной v, равно 2184 (888h)
 MsgBox myObj.Value ' 1092

End Sub

Как видно, в решении мы смогли добраться до внутренней переменной класса и искусственно повлиять на значения свойства класса Value.

Тем, кто заинтересовался задачей, посоветую в окне "Locals" (VBE) последить за значениями всех переменных класса clsValueKeeper. Там наглядно видно, что у объекта myObj есть 3 поля (переменных), хотя в коде доступно лишь одно - Value.

Каюсь - константы смещений offset_v и offset_w были подобраны "вручную", я пока не нашел точного описания, как именно инициированный объект (экземпляр) класса размещается в памяти, кроме того, что первые 8/16 байт для x86/x64 - это `заголовок` класса, следующие 4/8 байт - вспомогательные, и т.п.

Большое Спасибо уважаемому Казанскому за предложенный эксперимент, за помощь и активное участие в рассуждениях, а Ваш покорный слуга пока попробует применить полученные результаты для решения поставленной задачи топика - изменить свойство Value элемента Cells.Item(1,1).
Изменено: Alex.Karev - 22.02.2016 19:02:57
Записать значение в ячейку Excel с помощью win api
 
Казанский, спасибо за пояснения! Не скрою, не знал подробного механизма работы RtlMoveVemory и того, что RtlMoveVemory на самом деле не была задействована.

Я предполагал следующее:
  • предположим, открыта книга Excel (не сохранена на диске), в ячейку A1 занесено 555, курсор вышел из ячейки
  • число 555 где-то же хранится в памяти, и, кроме того, ассоциируется с элементом Cells(1,1)?
Тогда скажите, разве

Код
StrPtr(CStr(Cells(1, 1)))

не даёт указатель именно на строку `555` в памяти, что должно быть представлено байтами

Код
00 35 00 35 00 35

?

Про пояснение про 2048 отдельное спасибо - я бы не обратил внимание на этот момент. (Для неискушенных читателей) Имелось ввиду, что данные, занесённые в ячейку, хранятся в формате Unicode и занимают количество байт, равное двойному размеру длины строки. То есть строка `555` (3 символа на экране) == 6 байт в памяти.

Получается, если применить ReDim независимо от длины считываемой из ячейки строки, то считывание может выйти за пределы размера строки содержимого ячейки и "залезть" дальше, на область памяти в лучшем случае с пустыми, а в худшем случае - с "чужими" данными.
Изменено: Alex.Karev - 17.02.2016 18:57:43
Записать значение в ячейку Excel с помощью win api
 
Цитата
The_Prist написал: а зачем API для изменения значения ячейки?
The_Prist, спасибо, что заинтересовались, вопрос задан исключительно в познавательных целях, в частности, о возможностях работы с памятью, ускорении вычислений при работе с большими объёмами данных. Информации по VBA и win api не много, в основном на форумах, вот, пытаюсь разобраться.
Изменено: Alex.Karev - 17.02.2016 17:15:03
Записать значение в ячейку Excel с помощью win api
 
vikttur, спасибо! Прошу прощения за недосказанность и дополняю свой вопрос: а как это можно было бы реализовать с помощью win api?
Записать значение в ячейку Excel с помощью win api
 
Здравствуйте, уважаемые форумчане!

Считать значение ячейки A1 на текущем листе можно так:
Код
MsgBox ActiveSheet.Cells(1, 1).Value

А можно так:

Код
#If VBA7 Then

Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Dst As Any, Src As Any, ByVal bytes As Long)
#Else
Private Declare Sub RtlMoveMemory Lib "kernel32" (Dst As Any, Src As Any, ByVal bytes As Long)
#End If
'--------------------------
Sub test()
    Dim b() As Byte

    ReDim b(1 To 4096)
    RtlMoveMemory b(1), ByVal StrPtr(Cells(1, 1)), 4096
    MsgBox b
End Sub

Подскажите пожалуйста, а как можно и можно ли изменить значение этой ячейки с помощью win api?

Заранее благодарю за предложения.
Изменено: Alex.Karev - 17.02.2016 16:56:25
Страницы: 1
Наверх