Опять нужна Ваша помощь. Есть куча Excel-файлов с кучей формул. Надо макросом найти и скопировать все формулы в отдельную книгу в виде таблицы: "Имя книги-листа-ячейки" - "Значение" - "Формула без знака '='".
Т.е. получить нужный результат можно, задав на поиск в каждой книге символ "=". Скрин. Но его нельзя сохранить или вывести на лист. Понимаю, что нужно как-то зациклить поиск с выборкой результатов в массив и потом вывести массив на лист. Вроде всё просто, но при температуре почти 40º не могу сообразить - мозг просто плавится.
Sub t()
Dim x As Range, c As Range, i&
Set x = Sheets(1).UsedRange.SpecialCells(xlCellTypeFormulas, 23)
If Not x Is Nothing Then
For Each c In x.Cells
i = i + 1
Sheets(2).Cells(i, 1).Value = Mid(c.Formula, 2)
Next
End If
End Sub
galina mur, ikki, LightZ, огромное Вам спасибо! Попытался сделать универсальный макрос для поиска текста/формул в указанных xls*-файлах. Выдаёт результат в виде Файл - Лист - Ячейка - Формула - Значение. В информационных строках прописывает запрос, путь, число найденных результатов и время выполнения.
Осталось 2 вопроса:
1. Как сделать возможность выбора как папки, так и 1/нескольких файлов? Сейчас поиск идёт по всем файлам в папке... 2. Как сделать, чтобы имя файла/листа записывалось только при смене файла/листа? Сейчас прописывает эту информацию в каждой ячейке.
1. Почитайте справку про методы FileDialog'a 2. Используйте булевую переменную Ps. Почему Вы изменяете своё сообщение, а не пишете новое? Ведь если тема будет подыматься вверх - шансов, что Вам помогут больше.
Киса, я хочу Вас спросить, как художник — художника: Вы рисовать умеете?
Если изменяете так, что в последующих сообщениях искажается смысл или теряется привязка, то мусора становится больше. Обращайте на это вимание. Нужно учитывать, что посетители не перечитывают сообщения каждый раз при входе в тему и могут быть не в курсе новостей, которыми Вы напичкаете старые сообщения. Править/дополнять можно и нужно, но с умом.
Acid Burn, 1. С помощью FileDialog(msoFileDialogFilePicker) - зажимаете шифт и выделяете нужные Вам файлы или сразу все через Ctrl+A. 2. Пример кода можно. Покажите какой результат у Вас сейчас и какой должен быть. Также приложите часть кода, где выполняется нужный этап.
Киса, я хочу Вас спросить, как художник — художника: Вы рисовать умеете?
Так-то "результат" был выложен в посте #4. Вот код:
Код 1
' ВЫБОР ФАЙЛА / ГРУППЫ ФАЙЛОВ Set FD = Application.Application.FileDialog(3) With FD .AllowMultiSelect = True ' Не работает, несмотря на AllowMultiSelect .Title = "Выберите файл или группу файлов" If .Show = 0 Then Exit Sub Else iPath = Mid(.SelectedItems(1), 1, InStrRev(.SelectedItems(1), "\" ;) ) End With Set FD = Nothing
Код 2
' ВЫПОЛНЕНИЕ ПОИСКОВОГО ЗАПРОСА iTimer! = Timer Set iShFound = ActiveSheet Call Intro With Application iFile = Dir(iPath & "*.xls" ;) iCount = 0 Do While iFile$ <> "" Set iWB = Workbooks.Open(Filename:=iPath & iFile, ReadOnly:=True) For Each iSh In iWB.Sheets If iSh.FilterMode = True Then iSh.ShowAllData Set iRng = iSh.Cells.Find(What:=iFind, LookIn:=xlFormulas, LookAt:=xlPart) If Not iRng Is Nothing Then FoundAny = True firstAddress = iRng.Address Do With iShFound iLastRow = .Cells(.Rows.Count, 2).End(xlUp).Row + 1 .Cells(iLastRow, 2) = iWB.Name ' Имя файла (при переходе от файла к файлу - ?) .Cells(iLastRow, 3) = iSh.Name ' Имя листа (при переходе от листа к листу - ?) .Cells(iLastRow, 4) = iRng.Address ' Адрес ячейки .Cells(iLastRow, 5) = Mid(iRng.Formula, 2) ' Формула .Cells(iLastRow, 6) = iRng ' Значение End With Set iRng = iSh.Cells.FindNext(iRng) iCount = iCount + 1 Loop While iRng.Address <> firstAddress Else: End If Next iWB.Close SaveChanges:=False iFile = Dir Loop End With
А нужный результат Вы так и не приложили... Т.е. Вам нужно, чтобы названия листов и книг не дублировалось и просто были пустые ячейки? Если да - тогда необходимо вынести запись имён листа и книги за цикл Do.
Код
lLR = iShFound.Cells(Rows.Count, 4).End(xlUp).Row + 1
iShFound.Cells(lLR, 2) = iWB.Name ' Имя файла (при переходе от файла к файлу)
iShFound.Cells(lLR, 3) = iSh.Name ' Имя листа (при переходе от листа к листу)
Do
With iShFound
iLastRow = .Cells(.Rows.Count, 4).End(xlUp).Row + 1
.Cells(iLastRow, 4) = iRng.Address ' Адрес ячейки
.Cells(iLastRow, 5) = Mid(iRng.Formula, 2) ' Формула
.Cells(iLastRow, 6) = iRng ' Значение
End With
Киса, я хочу Вас спросить, как художник — художника: Вы рисовать умеете?
LightZ, Вы меня абсолютно правильно поняли. Но выносить запись имён листа и книги за цикл Do я уже пробовал - работает не правильно. С FileDialog тоже тромб... Похоже придётся рисовать форму и использовать Shell... (?)
1. Подумайте логически - как может работать неправильно?)) просто сделайте 2 переменные последней строки 2. Что не получается? Почему не подходит filedialog ?
Киса, я хочу Вас спросить, как художник — художника: Вы рисовать умеете?
1. Забыл изменить имя переменной. Теперь всё работает! Простите за невнимательность! 2. При работе с папкой, содержащей несколько файлов Excel, хотелось бы получить: а) возможность выбрать несколько файлов б) возможность выбрать только 1 файл в) автоматическую блокировку открытия файла-источника макроса (при его случайном выборе) Сейчас работает только вариант "а)".
LightZ, вот моя тестовая папка: Выборка.xlsb - файл с макросом поиска; Тест - папка с 2-мя файлами (01, 02). Попробуйте выбрать только поиск по файлу 01 - это будет пункт б), и он не работает. Затем попробуйте поместить в папку Тест файл Выборка.xlsb - это будет пункт в).
Посмотрел. А зачем вообще использовать Dir? Ведь можно сделать всё намного проще и обойтись только FileDialog'ом См. пример:
Код
Sub io()
Dim i&
With Application.FileDialog(msoFileDialogFilePicker)
.Show: If .SelectedItems.Count = 0 Then Exit Sub
For i = 1 To .SelectedItems.Count
MsgBox .SelectedItems(i)
Next
End With
End Sub
Киса, я хочу Вас спросить, как художник — художника: Вы рисовать умеете?
Кстати, да. Спасибо Вам, LightZ! Я что-то и не подумал. В новой версии: 1. Перестроил и сократил код 2. Ускорил очистку листа, заменил True/False на 0/1 (надеюсь, не перестарался) 3. Ввёл выдачу формул на русском 4. Добавил обработчик ошибок 5. Прикрутил более точный таймер Прогнал в реальных условиях: 246940 результатов за 05:03:626 мин. (~813 опер./сек.). Медленно...
LightZ, в посте #5 Вы предлагали предварительно занести данные в массив. Как это сделать?
>> Что? В смысле я заменил очистку 1048576 строк на очистку UsedRange. В логических операторах ввёл 0/1 вместо True/False, т.к. цифровые значения в VBA обрабатываются быстрее. Просто объединил в один пункт. >> aValues(), aFormuls() Тут не понял. Можно поподробнее?
Option Base 1
Sub tt()
Dim aValues(), aFormuls()
Dim i&, j&
Rem заносим в массив значения и формулы
With Лист1.UsedRange
aValues = .Value
aFormuls = .FormulaLocal
End With
Rem проходим циклом по строкам и столбцам массивов
For i = 1 To UBound(aFormuls)
For j = 1 To UBound(aFormuls, 2)
If aFormuls(i, j) <> Empty Then
Debug.Print aValues(i, j), " - значение"
Debug.Print aFormuls(i, j), " - формула"
Debug.Print Cells(i, j).Address, " - адрес"
End If
Next
Next
End Sub
В данном примере адрес можно получить только если в A1 есть значение. Ps. Советую почитать
LightZ, почитать и понять - разные вещи. На всё нужно время... За пример спасибо, правда адаптировать его не смог, только больше запутался. В принципе, 5 минут на 246940 результатов - не так уж и плохо. Предлагаю закрыть тему.
Один замечательный человек помог кардинально улучшить мой макрос. Теперь для любого количества файлов Excel можно получить: 1. Всю информацию в соответствии с запросом на одном листе 2. Перечень уникальных функций и операторов 3. Перечень уникальных формул (последовательностей функций) 4. Проанализировать, какие функции/формулы/операторы используются чаще всего