Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Microsoft Office и VBA программирование > Microsoft Office Excel
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.04.2010, 17:59   #1
motorway
Участник клуба
 
Регистрация: 28.06.2009
Сообщений: 1,950
Смущение Ускорить обработку строки, с использованием InStr

Привет всем.
Мне нужно ускорить обработку текстовой строки, я сделал один вариант кода, но он долго работает, если строка около 200 кБ. Поэтому надо переделать код без использования Split, а использовать InStr и Mid, т.е. посимвольную обработку (что может помочь).

Строка имеет вид:
Код:
Лист1~B2|value`C2|value`...`:::Лист2~B2|value`C2|value`:::Лист3~B2|value`C2|value`
Т.е., сначала идет название листа, далее разделитель ~, далее название ячейки, потом разделитель |, далее значение, потом разделитель ` и данные для следующей ячейки.
И так далее до разделителя между листами ":::". Если лист один, то такого разделителя не будет, соответственно.
Код обрабатывает эту строку и помещает результат value в соотв. ячейку на листе, например для ячейки B2 на Листе1 будет значение value и т.п. для других ячеек.

Сейчас у меня такой код:

Код:
List = Split(stack, ":::")
For Each l In List
Sheet = Split(l, "~")
sheetname = Sheet(0)
znach = Sheet(1)
zn = Split(znach, "`")
Set shname = Worksheets(sheetname)
For Each Z In zn
If (Len(Z)) Then
Data = Split(Z, "|")
yach = Data(0)
Value = Data(1)
shname.Range(yach).Value = Value
End If
Next Z
Next l
Кто может помочь переделать это с использованием InStr и Mid?

Последний раз редактировалось motorway; 06.04.2010 в 18:01.
motorway вне форума Ответить с цитированием
Старый 06.04.2010, 19:52   #2
SAS888
Старожил
 
Аватар для SAS888
 
Регистрация: 05.12.2007
Сообщений: 4,180
По умолчанию

Цитата:
код без использования Split, а использовать InStr и Mid, т.е. посимвольную обработку (что может помочь).
Уверяю Вас, что это будет еще медленнее. В данном случае, основное время затрачивается не на получение имен листов и адресов ячеек, а на обращение к ячейкам рабочих листов Excel.
Ну, и по коду: с какой целью выполняется проверка If (Len(Z)) Then ? Что, 2 разделителя значений подряд, это возможный вариант? Также, можно убрать лишние присваивания значений переменным. Т.е., примерно так:
Код:
List = Split(stack, ":::")
For Each l In List
    Sheet = Split(l, "~")
    zn = Split(Sheet(1), "`")
    Set shname = Sheets(Sheet(0))
    For Each Z In zn
    Data = Split(Z, "|")
        shname.Range(Data(0)) = Data(1)
    Next
Next
P.S. Если не секрет, прикрепите Вашу строку в 200 кБ, а мы посмотрим, как можно ускорить процесс обработки.
Чем шире угол зрения, тем он тупее.
SAS888 вне форума Ответить с цитированием
Старый 06.04.2010, 20:11   #3
motorway
Участник клуба
 
Регистрация: 28.06.2009
Сообщений: 1,950
По умолчанию

Насколько я помню, эту проверку я сделал, т.к. иногда возникали ошибки, если строка имела определенный вид (пустое значение или что-то подобное).
Пример строки прикрепил.
Да, вот в случае исп. вашего кода выдает ошибку Subscript out of range - видимо, там остается пустая строка.
Вложения
Тип файла: txt stack18.txt (118.8 Кб, 144 просмотров)

Последний раз редактировалось motorway; 06.04.2010 в 20:19. Причина: добавка после тестирования кода
motorway вне форума Ответить с цитированием
Старый 07.04.2010, 05:17   #4
SAS888
Старожил
 
Аватар для SAS888
 
Регистрация: 05.12.2007
Сообщений: 4,180
По умолчанию

Цитата:
пустое значение или что-то подобное
Да, действительно. Присутствуют непечатные символы. Проверка нужна.
Ваш код, практически, оптимален. Но, как я уже говорил, основное время макрос затрачивает на непосредственное обращение к ячейкам рабочего листа Excel. Поэтому, целесообразно лишний раз этого не делать. Тем более, что в исходной строке присутствует очень большое количество пустых значений. Существенно ускорить работу макроса можно, вставив такую проверку. Также, лучше запретить обновление экрана, т.к. при вставке данных на активный лист Excel будет отображать (прорисовывать) этот процесс.
Попробуйте выполнить макрос с этими добавлениями. Сравните время выполнения. С Вашего позволения, добавил процедуру выбора txt-файла для обработки.
Код:
Sub Main()
    Dim shname As Worksheet, f As String, List, l, zn, z, Sheet, Data, fso
    Application.ScreenUpdating = False: Set fso = CreateObject("Scripting.FileSystemObject")
    f = Application.GetOpenFilename("Text Files (*.txt), *.txt")
    If f = "False" Then Exit Sub
    List = Split(fso.OpenTextFile(f, 1).ReadAll, ":::")
    For Each l In List
        Sheet = Split(l, "~"): zn = Split(Sheet(1), "`"): Set shname = Sheets(Sheet(0))
        For Each z In zn
            If Application.Clean(z) <> "" Then
                Data = Split(z, "|")
                If Data(1) <> "" Then shname.Range(Data(0)) = Data(1)
    End If: Next: Next
End Sub
Пример во вложении. Еще раз повторю, что время выполнения добавленной проверки (If Data(1) <> "" Then...) существенно меньше, нежели вставка пустого значения в ячейку. Поэтому, при большом объеме пустых значений, получим ощутимый выигрыш по времени.
Вложения
Тип файла: rar Temp.rar (8.0 Кб, 17 просмотров)
Чем шире угол зрения, тем он тупее.

Последний раз редактировалось SAS888; 07.04.2010 в 05:29.
SAS888 вне форума Ответить с цитированием
Старый 07.04.2010, 19:15   #5
motorway
Участник клуба
 
Регистрация: 28.06.2009
Сообщений: 1,950
По умолчанию

Код скоро попробую. В данном случае строка была такой, но может быть и совершенно другой, где значений много, а пустых мало. Но в любом случае, если значение пустое, то его надо присвоить ячейке - там же может быть непустое.
Что-то мне кажется, что ускорить не получится просто так. Нужно менять сам принцип. Что-нибудь вроде вставки из csv файла.
motorway вне форума Ответить с цитированием
Старый 08.04.2010, 01:00   #6
doober
Старожил
 
Аватар для doober
 
Регистрация: 02.05.2009
Сообщений: 3,907
По умолчанию

Я думаю уважаемый SAS888 не обидится за то,что я взял его макрос за основу,но добавил свою обработку данных.Работает практически мнговенно.Но справедлив по столбец Z включительно
Если диапазон больше,надо немного доработать получение адреса самого последнего столбца

Код:

Sub Main()
    Dim shname As Worksheet, f As String, List, l, zn, z, Sheet, Data, fso
    Dim aa, bb, dat, Star
     Dim sl, ssl As String
      Dim nah, kond, end_D, dp, kk, kl, n As Long
    Application.ScreenUpdating = False: Set fso = CreateObject("Scripting.FileSystemObject")
    f = Application.GetOpenFilename("Text Files (*.txt), *.txt")
    If f = "False" Then Exit Sub
    List = Split(fso.OpenTextFile(f, 1).ReadAll, ":::")
    For Each l In List
        Sheet = Split(l, "~"):
        zn = Split(Sheet(1), "`"):
        Set shname = Sheets(Sheet(0))
        aa = zn(0): Star = Split(aa, "|"): bb = zn(UBound(zn) - 1)
         sl = Mid(aa, 1, 1): ssl = Mid(bb, 1, 1)
           nah = Asc(sl) - 64: kond = Asc(ssl) - 64
          end_D = Split(bb, "|"): dp = kond - nah + 1: kk = (UBound(zn)) / dp
          ReDim rezu(1 To kk, 1 To dp)
          kl = 0
        For n = 0 To (UBound(zn)) / dp - 1
           For m = 1 To dp
            dat = Split(zn(kl), "|")
              rezu(n + 1, m) = dat(1)
            kl = kl + 1
       Next: Next
    shname.Range(Star(0) & ":" & end_D(0)) = rezu
   Next
End Sub
Анализ,обработка данных Недорого
doober вне форума Ответить с цитированием
Старый 08.04.2010, 06:55   #7
SAS888
Старожил
 
Аватар для SAS888
 
Регистрация: 05.12.2007
Сообщений: 4,180
По умолчанию

О какой обиде Вы говорите? Мы делаем общее дело. Но...
1. Ваш вариант ограничен столбцом из 1-й буквы "A:Z" (оговорено).
2. Ваш вариант будет корректно работать только тогда, когда в строке для обработки адреса ячеек отсортированы по возрастанию?
3. При вставке значений массива на рабочий лист (обязательное условие - непрерывный диапазон), исходные значения в ячейках, адреса которых отсутствуют в текстовой строке будут утеряны.

Всвязи с этим, вопросы автору темы:
1. Какой максимально возможный диапазон рабочего листа может быть использован (макс. № строки и столбца)?
2. Могут ли адреса ячеек в строке следовать не по порядку, либо не подряд? Например:
"...Лист1~B2|11`M123|16`C2|22.. ."
или
"...Лист1~B2|11`E2|16`H2|22..."
Т.е. есть ли какая-либо закономерность в очереди адресов ячеек текстовой строки для каждого листа?
3. Данные из текстовой строки вставляются на пустой лист? Т.е. можно ли очищать уже имеющиеся на листе значения ячеек, отсутствующих в текстовой строке?
Чем шире угол зрения, тем он тупее.

Последний раз редактировалось SAS888; 08.04.2010 в 06:57.
SAS888 вне форума Ответить с цитированием
Старый 08.04.2010, 07:55   #8
alex77755
Форумчанин
 
Аватар для alex77755
 
Регистрация: 14.02.2009
Сообщений: 753
По умолчанию

Попадалось заметка, что значительная потеря времени идёт при обращении к Range. Уберите из процедуры так же и названия листов - тоже тормозят.
Бастрее, говорят, будет обращение:
Лист1.Cells(5,2)
помогу решить контрольные VB6, VBA (недорого)
Alex77755@mail.ru
alex77755 вне форума Ответить с цитированием
Старый 08.04.2010, 11:09   #9
doober
Старожил
 
Аватар для doober
 
Регистрация: 02.05.2009
Сообщений: 3,907
По умолчанию

ТО SAS888 Полностью с Вами согласен,
чтобы выработать оптимальный алгоритм,
надо полностью знать условия и принцип организации обмена информацией.Программно всегда решить можно любую практически,задачу
Анализ,обработка данных Недорого
doober вне форума Ответить с цитированием
Старый 08.04.2010, 17:57   #10
alvazor
Форумчанин
 
Регистрация: 02.07.2009
Сообщений: 122
По умолчанию

Да, спецы правы, в таком варианте все тормозит запись на лист!
Несколько изменил макрос - вначале формирую полный массив данных, потом уже запись его на лист, процесс разделил месиджами. Все хорошо видно (заодно и сбои с пустыми данными убрал)
Вложения
Тип файла: rar Ускорить.rar (9.9 Кб, 20 просмотров)
alvazor вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
задачи: на двумерные массивы,обработку строк,обработку текстовых файлов. (Паскаль) Yaro Помощь студентам 2 12.11.2009 12:55
Как ускорить попиксельную обработку изображения Дамир Общие вопросы .NET 1 02.11.2009 12:40
Сравнение текста InStr() SoFuWa Microsoft Office Excel 7 22.07.2009 14:38
Сравнение Instr(), Строчине и прописные буквы SoFuWa Microsoft Office Excel 2 30.05.2009 16:20