Страницы: 1
RSS
Поиск полных значений в файлах указанной папки
 
Здравствуйте!

С помощью запускаемого в файле "Тест подхватывания номеров.xlsm" единственного макроса я пытаюсь найти в выбираемой в ходе исполнения макроса папке среди .xls файлов находить  значения, как-либо совпадающие с каждым значением из второго столбца файла с макросом.  Шерстятся все листы и все задействованные диапазоны листов. Найденные значения вставляются справа от искомого значения в файле с макросом.
Вот код макроса:
Код
Sub Найти_полный_sn()
    Dim Путь As String, Файл As String, sn As Range, Совпадений As Integer, i%, rng As Range
    Dim sh As Worksheet
    Dim Книга As Excel.Workbook
    
    'выбираем папку с файлами-источниками информации
    With Application.FileDialog(msoFileDialogFolderPicker)
        .ButtonName = "OK"
        .Title = "Выберите папку, содержащую файлы Excel"
        If .Show = 0 Then
            Exit Sub
        End If
        Путь = .SelectedItems(1)
    End With
    Файл = Dir(PathName:=Путь + "\*.xls")
    i = 2
    Set sn = ActiveSheet.Cells(i, 2)
    
    Do Until sn.Value = "" 'пока не закончатся серийные номера в столбце
       Совпадений = 0
       Do Until Файл = "" 'пока не закончатся файлы в выбранной папке
           Set Книга = Workbooks.Open(Путь + "\" + Файл)
           For Each sh In Книга.Sheets 'поиск по листам
               sh.Activate
               Set rng = sh.UsedRange.Find(What:=sn.Value, LookIn:=xlValues, LookAt:=xlPart)
                If Not (rng Is Nothing) Then
                    Совпадений = 1
                    sn.Offset(0, Совпадений).Value = rng.Value
                    Do Until rng Is Nothing
                        Set rng = sh.UsedRange.FindNext(rng)
                        If Not (rng Is Nothing) Then
                            Совпадений = Совпадений + 1
                            sn.Offset(0, Совпадений).Value = rng.Value
                        End If
                    Loop
                End If
           Next sh
           Книга.Close
           Файл = Dir
       Loop
       i = i + 1
       sn = ActiveSheet.Cells(i, 2).Value 'следующий серийник
    Loop
    Set Книга = Nothing
End Sub
Возникли следующие неточности работы алгоритма, прошу помочь исправить:
1. Как остановить бесконечное зацикливание, возникающее в самом вложенном Do Loop(это поиск значения на отдельном листе)?
2.  Почему-то для первого номера первым находится не короткое значение 60802491, а сразу 23160802491. Почему пропускается первое имеющееся значение

Тестировать макрос можно на втором файле с названием "База с полными номерами.xls", который надо положить в выбираемую в ходе отработки макроса папку.
Изменено: borro - 26.10.2018 15:03:10
желаю всем счастья
 
Цитата
borro написал:
Как остановить бесконечное зацикливание, возникающее в самом вложенном Do Loop(это поиск значения на отдельном листе)?
вставте счетчик i,j,k и т.п.
или проверку на пусто
Код
if sn = "" then goto metka1
после loop вставте
metka1:

должно получиться
Код
       i = i + 1
       sn = ActiveSheet.Cells(i, 2).Value 'следующий серийник
      if sn = "" then goto metka1
    Loop
metka1:
Цитата
2.  Почему-то для первого номера первым на
потому что вконце а не в начале цыкла
Код
sn = ActiveSheet.Cells(i, 2).Value 'следующий серийник
Изменено: ivanok_v2 - 26.10.2018 15:28:04
 
ivanok_v2, спасибо. Да, когда берется следующий серийник должно быть:
Код
set sn = ActiveSheet.Cells(i, 2) 'следующий серийник
Правда речь о зацикливании была не про этот Do Loop, а про Do Until rng Is Nothing
Изменено: borro - 26.10.2018 15:44:39
желаю всем счастья
 
Цитата
borro написал:
Почему пропускается первое имеющееся значение
Потому что для метода Find "первое" — не самое похожее, а первое, заданное направлением поиска.
Цитата
borro написал:
Как остановить бесконечное зацикливание
Код
Set FirstCell=rng
Do
Set rng = sh.UsedRange.FindNext(rng)
If Not (rng Is FirstCell) Then
Совпадений = Совпадений + 1
sn.Offset(0, Совпадений).Value = rng.Value
Else: Exit Do
End If
Loop
Изменено: StoTisteg - 26.10.2018 16:03:10
 
StoTisteg, спасибо!

Там же есть и второе условие выхода из цикла - ненахождение искомого значения на листе при следующей итерации FindNext. Попробовал это воплотить все в коде:
Код
Sub Найти_полный_sn()
    Dim Путь As String, Файл As String, sn As Range, FirstCell As Range, Совпадений As Integer
    Dim sh As Worksheet
    Dim Книга As Excel.Workbook
    
    'выбираем папку с файлами-источниками информации
    With Application.FileDialog(msoFileDialogFolderPicker)
        .ButtonName = "OK"
        .Title = "Выберите папку, содержащую файлы Excel"
        If .Show = 0 Then
            Exit Sub
        End If
        Путь = .SelectedItems(1)
    End With
    Файл = Dir(PathName:=Путь + "\*.xls")
    i = 2
    Set sn = ActiveSheet.Cells(i, 2)
    
    Do Until sn.Value = "" 'пока не закончатся серийные номера в столбце
       Совпадений = 0
       Do Until Файл = "" 'пока не закончатся файлы в выбранной папке
           Set Книга = Workbooks.Open(Путь + "\" + Файл)
           For Each sh In Книга.Sheets 'поиск по листам
               sh.Activate
               Set rng = sh.UsedRange.Find(What:=sn.Value, LookIn:=xlValues, LookAt:=xlPart)
                If Not (rng Is Nothing) Then
                    Set FirstCell = rng
                    If Совпадений = 0 Then
                        Совпадений = 1
                    Else
                        Совпадений = Совпадений + 1
                    End If
                    sn.Offset(0, Совпадений).Value = rng.Value
                    Do Until rng Is Nothing Or rng Is FirstCell
                        Set rng = sh.UsedRange.FindNext(rng)
                        If Not (rng Is Nothing) Then
                            Совпадений = Совпадений + 1
                            sn.Offset(0, Совпадений).Value = rng.Value
                        End If
                    Loop
                End If
           Next sh
           Книга.Close
           Файл = Dir
       Loop
       i = i + 1
       Set sn = ActiveSheet.Cells(i, 2) 'следующий серийник
    Loop
    Set Книга = Nothing
End Sub
некорректно работает. Для первого значения только одно значение находится из файла-источника. А должно быть три - 60802491, 23160802491, 6080249112321
Изменено: borro - 26.10.2018 16:21:53
желаю всем счастья
 
borro, лучше тогда не использовать find, а перебрать в цыкле с использованием Like
Изменено: ivanok_v2 - 26.10.2018 19:50:44
 
Читаем здесь (в частности, про параметр LookAt)
Изменено: sokol92 - 26.10.2018 20:05:31
Владимир
 
Цитата
sokol92 написал:
Читаем  здесь  (в частности, про параметр LookAt)
Добрый день! Спасибо. Я так и ищу, через xlPart
желаю всем счастья
 
Do Until
Loop Until
Хорошо забытое старое становится новым только после того, как вы это новое попробовали поискать
 
Код
If Совпадений = 0 Then
    Совпадений = 1
Else
    Совпадений = Совпадений + 1
End If
интересный подход. Но если вдуматься - когда совпадений 0, то если просто прибавить 1, то будет так же 1. Поэтому If здесь вообще не нужен и достаточно оставить только одну строку:
Код
Совпадений = Совпадений + 1
sh.Activate - тоже лишнее, т.к. далее обращаетесь все равно к конкретному листу.
И в общем код должен выглядеть так:
Код
Sub Найти_полный_sn()
    Dim Путь As String, Файл As String, sn As Range, Совпадений As Integer, i%, rng As Range
    Dim sh As Worksheet, shAct As Worksheet
    Dim Книга As Excel.Workbook
    Dim s As String
    
    Set shAct = ActiveSheet
    'выбираем папку с файлами-источниками информации
    With Application.FileDialog(msoFileDialogFolderPicker)
        .ButtonName = "OK"
        .Title = "Выберите папку, содержащую файлы Excel"
        If .Show = 0 Then
            Exit Sub
        End If
        Путь = .SelectedItems(1)
    End With
    Файл = Dir(PathName:=Путь + "\*.xls")
    i = 2
    Set sn = shAct.Cells(i, 2)
    
    Do Until sn.Value = "" 'пока не закончатся серийные номера в столбце
       Do Until Файл = "" 'пока не закончатся файлы в выбранной папке
           Set Книга = Workbooks.Open(Путь + "\" + Файл)
           For Each sh In Книга.Sheets 'поиск по листам
'               sh.Activate
                Set rng = sh.UsedRange.Find(What:=sn.Value, LookIn:=xlValues, LookAt:=xlPart)
                If Not (rng Is Nothing) Then
                    s = rng.Address
                    Do
                        Set rng = sh.UsedRange.FindNext(rng)
                        If Not (rng Is Nothing) Then
                            Совпадений = Совпадений + 1
                            sn.Offset(0, Совпадений).Value = rng.Value
                        End If
                    Loop Until rng Is Nothing Or rng.Address = s
                End If
           Next sh
           Книга.Close
           Файл = Dir
       Loop
       i = i + 1
       Совпадений = 0
       Set sn = shAct.Cells(i, 2) 'берем следующий серийник
    Loop
    Set Книга = Nothing
End Sub
Изменено: Дмитрий(The_Prist) Щербаков - 29.10.2018 17:09:11
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Хотя нет, не поможет.
Я бы сей кусок написал так
Код
Sub br()
    ' Set sh = ActiveSheet
    Set Rng = sh.UsedRange.Find(What:="a", LookIn:=xlValues, LookAt:=xlPart)
    If Not (Rng Is Nothing) Then
        s = Rng.Address
        Совпадений = Совпадений + 1
        Do
            Set Rng = sh.UsedRange.FindNext(Rng)
            If Rng.Address = s Then s = "": Set Rng = Nothing: Exit Do
            Совпадений = Совпадений + 1
        Loop
    End If
End Sub
Изменено: RAN - 29.10.2018 18:12:45
 
Всем спасибо!
Дмитрий, да, я сам улыбался своей логике сегодня :)
С учетом ваших предложений получилось следующая окончательная работающая версия:
Код
Sub Найти_полный_sn()
    Dim Путь As String, Файл As String, sn As Range, FirstCell As Range, Совпадений As Integer, cell As Range, s$
    Dim sh As Worksheet
    Dim Книга As Excel.Workbook
    
    'выбираем папку с файлами-источниками информации
    With Application.FileDialog(msoFileDialogFolderPicker)
        .ButtonName = "OK"
        .Title = "Выберите папку, содержащую файлы Excel"
        If .Show = 0 Then
            Exit Sub
        End If
        Путь = .SelectedItems(1)
    End With
    Файл = Dir(PathName:=Путь + "\*.xls")
    i = 2
    Set sn = ActiveSheet.Cells(i, 2)
    
    Do Until sn.Value = "" 'пока не закончатся серийные номера в столбце
       Совпадений = 0
       Do Until Файл = "" 'пока не закончатся файлы в выбранной папке
           Set Книга = Workbooks.Open(Путь + "\" + Файл)
           For Each sh In Книга.Sheets 'поиск по листам
               Set rng = sh.UsedRange.Find(What:=sn.Value, LookIn:=xlValues, LookAt:=xlPart)
                If Not (rng Is Nothing) Then
                    s = rng.Address
                    Совпадений = Совпадений + 1
                    sn.Offset(0, Совпадений).Value = rng.Value & " из "  & Файл
                    Do
                        Set rng = sh.UsedRange.FindNext(rng)
                        If Not (rng Is Nothing) And rng.Address <> s Then
                            Совпадений = Совпадений + 1
                            sn.Offset(0, Совпадений).Value = rng.Value & " из " & Файл
                        End If
                    Loop Until rng Is Nothing Or rng.Address = s
                End If

           Next sh
           
           Книга.Close
           Файл = Dir
       Loop
       i = i + 1
       Set sn = ActiveSheet.Cells(i, 2) 'следующий серийник
       Файл = Dir(PathName:=Путь + "\*.xls")
    Loop
    Set Книга = Nothing
End Sub
желаю всем счастья
 
Здравствуйте!

Скажите, пожалуйста, как можно адаптировать предыдущий мною выложенный код так, чтобы поиск слова(строки) шел рекурсивно и по всем подпапкам? Сейчас он только по файлам выбранной папки ищет.

Я попробовал пойти вторым путем - доработать пример, найденный в интернете, но получилось громоздко с двумя процедурами, и я  пока не знаю, как заставить программу автоматом отвечать "Не обновлять ссылки" в открываемом файле, плюс автоматом предварительно восстанавливать поврежденные эксель-файлы при их открытии. Вот что пока получилось:
Код
Dim objFSO As Object, objFolder As Object, objFile As Object, Совпадений As Integer

Sub Get_All_from_SubFolders()
    Dim sFolder As String
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show = False Then Exit Sub
        sFolder = .SelectedItems(1)
    End With
    sFolder = sFolder & IIf(Right(sFolder, 1) = Application.PathSeparator, "", Application.PathSeparator)
    Application.ScreenUpdating = False
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    
    i = 2
    Set sn = ActiveSheet.Cells(i, 1)
    
    Do Until sn.value = "" 'пока не закончатся серийные номера в столбце
       Совпадений = 0
       GetSubFolders sFolder, sn, Совпадений
       Set objFolder = Nothing
       Set objFSO = Nothing

       i = i + 1
       Set sn = ActiveSheet.Cells(i, 1) 'следующий серийник
    Loop
    
    Application.ScreenUpdating = True
End Sub

Private Sub GetSubFolders(sPath, sn, Совпадений)
    Dim sPathSeparator As String, sObjName As String, rng As Range
    Dim sh As Worksheet
    
    Set objFolder = objFSO.GetFolder(sPath)
    For Each objFile In objFolder.Files
        If Replace(objFile.Name, objFSO.GetBaseName(objFile), "") Like ".xls*" Then
            'открываем книгу
            Workbooks.Open sPath & objFile.Name
                For Each sh In ActiveWorkbook.Sheets 'поиск по листам
                   Set rng = sh.UsedRange.Find(What:=sn.value, LookIn:=xlValues, LookAt:=xlPart)
                    If Not (rng Is Nothing) Then
                        s = rng.Address
                        Совпадений = Совпадений + 1
                        sn.Offset(0, Совпадений).value = rng.value & " " & rng.Offset(0, -1).value & " в " & sPath & objFile.Name
                        Do
                            Set rng = sh.UsedRange.FindNext(rng)
                            If Not (rng Is Nothing) And rng.Address <> s Then
                                Совпадений = Совпадений + 1
                                sn.Offset(0, Совпадений).value = rng.value & " " & rng.Offset(0, -1).value & " в " & sPath & objFile.Name
                            End If
                        Loop Until rng Is Nothing Or rng.Address = s
                    End If
    
                Next sh
            ActiveWorkbook.Close True
        End If
    Next
    For Each objFolder In objFolder.SubFolders
        GetSubFolders objFolder.Path & Application.PathSeparator, sn, Совпадений
    Next
End Sub
Буду благодарен, если подскажите, каким путем идти
Изменено: borro - 10.12.2018 19:31:36
желаю всем счастья
 
похоже для моего второго пути решения задачи надо открывать файлы как
Код
Workbooks.Open sPath & objFile.Name, 0, , , , , , , , , , , , , xlRepairFile
желаю всем счастья
Страницы: 1
Наверх