1

Тема: VBScript: Поиск и автозамена данных в .xls

Добрый день форумчане! Возможно и есть похожая тема здесь, но подходящей я так и не нашёл... возможно и в силу того что я слаб в "Excel.Application".
А вопрос вот в чём: есть документ Excel-евский и там множество id-номеров, которые нужно заменить на человеческие имена. База сопоставления номеров их владельцам в текстовом файле id.txt вида:

Вася 3435664
Володя 5448
Егор 384475481
...

(разделитель vbTab)

Стремление - залог успеха

2

Re: VBScript: Поиск и автозамена данных в .xls

Почему просто не откроете текстовый файл в Excel с выполнением процедуры "Текст по столбцам"?

3

Re: VBScript: Поиск и автозамена данных в .xls

Дело в том что, это действие выполняется не однократно и: в самих ячейках с id-данными находится и другая информация(не шаблонно). Т.е. мне нужна простая идентификация и подмена id в теле документа на те, что из ключа.

Стремление - залог успеха

4

Re: VBScript: Поиск и автозамена данных в .xls

Lucky пишет:

... в самих ячейках с id-данными находится и другая информация(не шаблонно)...

Приложите пример рабочей книги. Реальные данные можете заменить на вымышленные.

5

Re: VBScript: Поиск и автозамена данных в .xls

       A1               A2
1  '+3435664         
2                    '-5448<4    
3                    '+48244>4   
4  384475481+
5                    558477>0
6                    '--4887<<0

Вот пример. Может как-нибудь думал простую и верную Replace() вживить, только файл бинарный.

Стремление - залог успеха

6

Re: VBScript: Поиск и автозамена данных в .xls

1. Идентификаторы пользователей расположены на листе беспорядочно?
2. Есть ли на листе определённые границы, в рамках которых размещаются идентификаторы?
3. Что в константе --4887<<0 является идентификатором?
4. Возможны ли повторения идентификаторов на листе и (или) в текстовом файле?

7

Re: VBScript: Поиск и автозамена данных в .xls

Dmitrii пишет:

1. Идентификаторы пользователей расположены на листе беспорядочно?
2. Есть ли на листе определённые границы, в рамках которых размещаются идентификаторы?
3. Что в константе --4887<<0 является идентификатором?
4. Возможны ли повторения идентификаторов на листе и (или) в текстовом файле?

1. Да.
2. В основном столбцы Е1 и А1. (хотя бы скажем пусть будет только Е1, если сложность в этом).
3. -4887
4. На листе Excel - любое кол-во повторений, но в текстовом файле (ключ) одному идентификатору соответствует только одно Имя, хоть и имена могут совпадать, учитывая совпадения имён людей.

Стремление - залог успеха

8 (изменено: Dmitrii, 2011-05-11 15:49:06)

Re: VBScript: Поиск и автозамена данных в .xls

Ну, если я правильно понял Вашу задачу, то в качестве базового варианта должен подойти такой макрос:


Option Compare Text

Sub Example()
Dim objFS As FileSystemObject, objFile As TextStream, strPath As String
Dim arrTemp, arrIDs() As String, arrNames() As String
Dim strTemp, lngTemp As Long, i As Long, j As Long
Dim objNonEmptyCells As Range, objItem As Range

strPath = "C:\Temp\id.txt"
Set objFS = New FileSystemObject
If objFS.FileExists(strPath) Then
    If objFS.GetFile(strPath).Size > 0 Then
        Set objFile = objFS.OpenTextFile(strPath, ForReading)
        strTemp = objFile.ReadAll
        objFile.Close
        Set objFile = Nothing
        arrTemp = Split(strTemp, vbNewLine)
        lngTemp = UBound(arrTemp)
        j = -1
        For i = 0 To lngTemp
            If Len(arrTemp(i)) > 0 Then
                j = j + 1
                ReDim Preserve arrIDs(j): ReDim Preserve arrNames(j)
                strTemp = Split(arrTemp(i), vbTab)
                arrIDs(j) = strTemp(1)
                arrNames(j) = strTemp(0)
            End If
        Next
        Erase arrTemp
        On Error Resume Next
        Set objNonEmptyCells = Worksheets(1).Cells.SpecialCells(xlCellTypeConstants)
        If Err.Number = 0 Then
            On Error GoTo 0
            For Each objItem In objNonEmptyCells
                strTemp = objItem.Value
                For i = 0 To UBound(arrIDs)
                    If InStr(strTemp, arrIDs(i)) > 0 Then
                        objItem.Value = Replace(strTemp, arrIDs(i), arrNames(i))
                        Exit For
                    End If
                Next
            Next
            Set objNonEmptyCells = Nothing
            Erase arrIDs: Erase arrNames
            MsgBox "Готово.", vbInformation
        Else
            Err.Clear
            MsgBox "Рабочий лист не содержит строковых констант.", vbCritical
        End If
    Else
        MsgBox "Файл " & UCase(strPath) & " пуст.", vbCritical
    End If
Else
    MsgBox "Путь " & UCase(strPath) & " не найден.", vbCritical
End If
Set objFS = Nothing
End Sub

Примечания.
1. Предполагается, что анализируемые данные находятся на первом по порядку листе рабочей книги.
2. Обязательно подключите к проекту библиотеку Microsoft Scripting Runtime (файл именуется scrrun.dll).
3. Макрос проверен для Excel 2003.

9

Re: VBScript: Поиск и автозамена данных в .xls

Вариант макроса с диалогом выбора файла со списком сопоставлений:


Option Compare Text

Sub Example2()
Dim objFS As FileSystemObject, objFile As TextStream, strPath As String
Dim arrTemp, arrIDs() As String, arrNames() As String
Dim strTemp, lngTemp As Long, i As Long, j As Long
Dim objNonEmptyCells As Range, objItem As Range

With Application.FileDialog(msoFileDialogOpen)
    .AllowMultiSelect = False
    .Filters.Clear
    .Filters.Add "Простой текст", "*.txt"
    .Show
    If .SelectedItems.Count = 1 Then
        strPath = .SelectedItems(1)
    End If
End With
If Len(strPath) > 0 Then
    Set objFS = New FileSystemObject
    If objFS.GetFile(strPath).Size > 0 Then
        Set objFile = objFS.OpenTextFile(strPath, ForReading)
        strTemp = objFile.ReadAll
        objFile.Close
        Set objFile = Nothing
        arrTemp = Split(strTemp, vbNewLine)
        lngTemp = UBound(arrTemp)
        j = -1
        For i = 0 To lngTemp
            If Len(arrTemp(i)) > 0 Then
                j = j + 1
                ReDim Preserve arrIDs(j): ReDim Preserve arrNames(j)
                strTemp = Split(arrTemp(i), vbTab)
                arrIDs(j) = strTemp(1)
                arrNames(j) = strTemp(0)
            End If
        Next
        Erase arrTemp
        On Error Resume Next
        Set objNonEmptyCells = Worksheets(1).Cells.SpecialCells(xlCellTypeConstants)
        If Err.Number = 0 Then
            On Error GoTo 0
            For Each objItem In objNonEmptyCells
                strTemp = objItem.Value
                For i = 0 To UBound(arrIDs)
                    If InStr(strTemp, arrIDs(i)) > 0 Then
                        objItem.Value = Replace(strTemp, arrIDs(i), arrNames(i))
                        Exit For
                    End If
                Next
            Next
            Set objNonEmptyCells = Nothing
            Erase arrIDs: Erase arrNames
            MsgBox "Готово.", vbInformation
        Else
            Err.Clear
            MsgBox "Рабочий лист не содержит строковых констант.", vbCritical
        End If
    Else
        MsgBox "Файл " & UCase(strPath) & " пуст.", vbCritical
    End If
    Set objFS = Nothing
Else
    MsgBox "Файл не выбран.", vbCritical
End If
End Sub

10

Re: VBScript: Поиск и автозамена данных в .xls

Спасибо вам огромное, Dmitrii, увы пока я зашел с телефона и по техническим причинам не смогу проверить в ближайшее время, как проверю сообщу результат... Примногом благодарен вам за помощь!

Стремление - залог успеха

11 (изменено: Lucky, 2011-05-17 14:07:08)

Re: VBScript: Поиск и автозамена данных в .xls

Просмотрел ваши скрипты и как я понял там мы работаем непосредственно в VBA, открывая документ Excel (если ошибаюсь - поправьте, т.к. в макросах ни сколько не шарю, да и заюзать скрипт не смог), ну а хотелось бы работать именно с .vbs.
В голове есть идеи, но они годны лишь отчасти (только к текстовой части...), вот кусочек самого кода:


set FSO = CreateObject("Scripting.FileSystemObject")

file="1.txt"
text=FSO.OpenTextFile(file,1).ReadAll()

key="id.txt"
book=FSO.OpenTextFile(key,1).ReadAll()
book=Split(book,vbCrLf)

For each bookLine in book
  ab=Split(bookLine,vbTab)
  text=RePlace(text,ab(1),ab(0))
Next

FSO.OpenTextFile("out_"&file,2,true).Write(text)

и решением пока вижу применять этот код к сценарию внутри Excel-книги (пока копи-пастом вручную, но в перспективе хотелось бы довести до автоматики), но как я писал ранее не могу пропарсить бинарный файл vbs-скриптом. Может есть какие соображения у вас?

Стремление - залог успеха

12

Re: VBScript: Поиск и автозамена данных в .xls

Lucky пишет:

... заюзать скрипт не смог...

Почему?

Lucky пишет:

... хотелось бы работать именно с .vbs...

В теме WSH: преобразуем макрос VBA в скрипт VBScript есть руководство к действию.

Lucky пишет:

... применять этот код к сценарию внутри Excel-книги...

Не могу понять эту фразу.

Lucky пишет:

... не могу пропарсить бинарный файл vbs-скриптом...

Вы пытаетесь обрабатывать рабочую книгу Excel, не имея самого приложения?

13 (изменено: Lucky, 2011-05-17 17:27:05)

Re: VBScript: Поиск и автозамена данных в .xls

Dmitrii пишет:
Lucky пишет:

... заюзать скрипт не смог...

Почему?

Начну по-порядку, база моих знаний в VBA - 3 недели семестровых занятий, но тем не менее теперь по нужде разобрался с подключением к проекту библиотеки Microsoft Scripting Runtime. В итоге запускаю - в ответ в полне логичное сообщение "Готово", но на деле в листе Excel все те же самые номера...

Dmitrii пишет:
Lucky пишет:

... хотелось бы работать именно с .vbs...

В теме WSH: преобразуем макрос VBA в скрипт VBScript есть руководство к действию.

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

Dmitrii пишет:
Lucky пишет:

... применять этот код к сценарию внутри Excel-книги...

Не могу понять эту фразу.

Если обратили внимание, мой скрипт с поста #11 как раз и парсит текстовый файл txt, заменяя там все id-совпадения с ключа id.txt, но вот этим его функциональность и ограничивается. Но для себя я нашёл некоторый альтернативный выход из ситуации: У листов Excel я открываю их сценарии (Сервис->Макрос->Редактор сценариев) и копирую это текстовое представление листа в file.txt, затем обрабатываю его своим скриптом и обратно вставляю в Excel-лист. Вот такой вот механизм полу-автомат .

Dmitrii пишет:
Lucky пишет:

... не могу пропарсить бинарный файл vbs-скриптом...

Вы пытаетесь обрабатывать рабочую книгу Excel, не имея самого приложения?

Есть у меня MS Office, только вот хотелось бы провести все действия без него, а им уж только любоваться результатом .

Стремление - залог успеха

14

Re: VBScript: Поиск и автозамена данных в .xls

Lucky пишет:

... У листов Excel я открываю их сценарии (Сервис->Макрос->Редактор сценариев)...

1. Откройте редактор VBA (Сервис->Макрос->Редактор Visual Basic).
2. В пункте Insert главного меню выберите пункт Module.
3. В появившееся окно кода этого модуля вставьте любой из предложенный мной вариантов макроса (ему место там).

Lucky пишет:

... Есть у меня MS Office, только вот хотелось бы провести все действия без него...

Минимально, что Вам для этого потребуется,- изучить формат файлов с рабочими книгами. Задача эта явно намного сложнее, чем та, которую Вам требуется сейчас решить (замена индексов на имена).
Мой совет: сначала хорошенько освойте возможности самого Excel.

Lucky пишет:

... моих знаний пока недостаточно и для запуска оного скрипта, не говоря уж об анализе и конвертировании...

Если завтра будет досуг - переделаю макрос в сценарий.

15

Re: VBScript: Поиск и автозамена данных в .xls

Dmitrii пишет:
Lucky пишет:

... У листов Excel я открываю их сценарии (Сервис->Макрос->Редактор сценариев)...

1. Откройте редактор VBA (Сервис->Макрос->Редактор Visual Basic).
2. В пункте Insert главного меню выберите пункт Module.
3. В появившееся окно кода этого модуля вставьте любой из предложенный мной вариантов макроса (ему место там).

Я проделывал ранее то, что вы сейчас написали, более того, писал разобрался с подключением к проекту библиотеки Microsoft Scripting Runtime (кстати, его приходится подключать каждый раз) и получал в ответ "Готово", но индексы так и оставались нетронутыми. Но, проделал то же самое сейчас - получилось! Спасибо вам! Как я понял он обрабатывает только первый лист Теперь с нетерпением жду (и пробую вникать) переделки макроса в сценарий чтоб не возиться с копипастами (кстати, интересно получилось в моём способе - это был копипаст тела листа, а в вашем - кода макроса).

Стремление - залог успеха

16

Re: VBScript: Поиск и автозамена данных в .xls

Lucky пишет:

... разобрался с подключением к проекту библиотеки Microsoft Scripting Runtime (кстати, его приходится подключать каждый раз)...

Так не должно быть. Один раз настроенная в проекте ссылка должна оставаться до того момента, пока Вы её не отключите.
Как именно выполняли подключение?

Lucky пишет:

... он обрабатывает только первый лист...

Да. Если надо обрабатывать другие листы (все или часть из них), потребуется организовать соответствующий цикл.

Lucky пишет:

... жду (и пробую вникать) переделки макроса в сценарий...

Вариант 1 (без диалога выбора файла и книги).

Dim objFS, objFile, strFile
Dim objExcel, objWB, strBook
Dim objNonEmptyCells, objItem
Dim arrTemp, arrIDs(), arrNames()
Dim strTemp, lngTemp, i, j

strFile = "C:\Temp\id.txt"
strBook = "C:\Temp\book.xls"
Set objFS = CreateObject("Scripting.FileSystemObject")
If objFS.FileExists(strFile) Then
    If objFS.GetFile(strFile).Size > 0 Then
        Set objFile = objFS.OpenTextFile(strFile, 1)
        strTemp = objFile.ReadAll
        objFile.Close
        Set objFile = Nothing
        arrTemp = Split(strTemp, vbNewLine)
        lngTemp = UBound(arrTemp)
        j = -1
        For i = 0 To lngTemp
            If Len(arrTemp(i)) > 0 Then
                j = j + 1
                ReDim Preserve arrIDs(j): ReDim Preserve arrNames(j)
                strTemp = Split(arrTemp(i), vbTab)
                arrIDs(j) = strTemp(1)
                arrNames(j) = strTemp(0)
            End If
        Next
        Erase arrTemp
        If objFS.FileExists(strBook) Then
            Set objExcel = CreateObject("Excel.Application")
            Set objWB = objExcel.Workbooks.Open(strBook)
            On Error Resume Next
            Set objNonEmptyCells = objWB.Worksheets(1).Cells.SpecialCells(2)
            If Err.Number = 0 Then
                On Error GoTo 0
                For Each objItem In objNonEmptyCells
                    strTemp = objItem.Value
                    For i = 0 To UBound(arrIDs)
                        If InStr(strTemp, arrIDs(i)) > 0 Then
                            objItem.Value = Replace(strTemp, arrIDs(i), arrNames(i))
                            Exit For
                        End If
                    Next
                Next
                Set objNonEmptyCells = Nothing
                Erase arrIDs: Erase arrNames
                objWB.Save
                WScript.Echo "Готово."
            Else
                Err.Clear
                objWB.Saved = True
                WScript.Echo "Рабочий лист не содержит строковых констант."
            End If
            objWB.Close
            Set objWB = Nothing
            objExcel.Quit
            Set objExcel = Nothing
        Else
            WScript.Echo "Путь " & UCase(strBook) & " не найден."
        End If
    Else
        WScript.Echo "Файл " & UCase(strFile) & " пуст."
    End If
Else
    WScript.Echo "Путь " & UCase(strFile) & " не найден."
End If
Set objFS = Nothing
WScript.Quit 0

Вариант 2 (с диалогом выбора файла и книги).

Dim objFS, objFile, strFile
Dim objExcel, objWB, strBook
Dim objNonEmptyCells, objItem
Dim arrTemp, arrIDs(), arrNames()
Dim strTemp, lngTemp, i, j

Set objExcel = CreateObject("Excel.Application")
With objExcel.FileDialog(1)
    .AllowMultiSelect = False
    .Filters.Clear
    .Filters.Add "Простой текст", "*.txt"
    .Show
    If .SelectedItems.Count = 1 Then
        strFile = .SelectedItems(1)
    End If
End With
If Len(strFile) > 0 Then
    Set objFS = CreateObject("Scripting.FileSystemObject")
    If objFS.GetFile(strFile).Size > 0 Then
        Set objFile = objFS.OpenTextFile(strFile, 1)
        strTemp = objFile.ReadAll
        objFile.Close
        Set objFile = Nothing
        arrTemp = Split(strTemp, vbNewLine)
        lngTemp = UBound(arrTemp)
        j = -1
        For i = 0 To lngTemp
            If Len(arrTemp(i)) > 0 Then
                j = j + 1
                ReDim Preserve arrIDs(j): ReDim Preserve arrNames(j)
                strTemp = Split(arrTemp(i), vbTab)
                arrIDs(j) = strTemp(1)
                arrNames(j) = strTemp(0)
            End If
        Next
        Erase arrTemp
        With objExcel.FileDialog(1)
            .AllowMultiSelect = False
            .Filters.Clear
            .Filters.Add "Рабочая книга Excel", "*.xls"
            .Show
            If .SelectedItems.Count = 1 Then
                strBook = .SelectedItems(1)
            End If
        End With
        objExcel.Visible = False
        If Len(strBook) > 0 Then
            Set objWB = objExcel.Workbooks.Open(strBook)
            On Error Resume Next
            Set objNonEmptyCells = objWB.Worksheets(1).Cells.SpecialCells(2)
            If Err.Number = 0 Then
                On Error GoTo 0
                For Each objItem In objNonEmptyCells
                    strTemp = objItem.Value
                    For i = 0 To UBound(arrIDs)
                        If InStr(strTemp, arrIDs(i)) > 0 Then
                            objItem.Value = Replace(strTemp, arrIDs(i), arrNames(i))
                            Exit For
                        End If
                    Next
                Next
                Set objNonEmptyCells = Nothing
                Erase arrIDs: Erase arrNames
                objWB.Save
                WScript.Echo "Готово."
            Else
                Err.Clear
                objWB.Saved = True
                WScript.Echo "Рабочий лист не содержит строковых констант."
            End If
            objWB.Close
            Set objWB = Nothing
            objExcel.Quit
        Else
            WScript.Echo "Файл с рабочей книгой не выбран."
        End If
    Else
        WScript.Echo "Файл " & UCase(strFile) & " пуст."
    End If
    Set objFS = Nothing
Else
    WScript.Echo "Файл с таблицей сопоставления не выбран."
End If
Set objExcel = Nothing
WScript.Quit 0

17

Re: VBScript: Поиск и автозамена данных в .xls

Dmitrii пишет:

Один раз настроенная в проекте ссылка должна оставаться до того момента, пока Вы её не отключите.
Как именно выполняли подключение?

Нагуглил такую инструкцию:

1. Запустите одно из приложений MS Office..
2. В меню "Сервис" выберите пункт "Макрос" и запустите команду "Редактор Visual Basic".
3. В окне "Microsoft Visual Basic" откройте меню "Сервис" ("Tools") и запустите команду "Ссылки" ("References").
4. В списке "Доступные ссылки" ("Available References") установите флажок напротив библиотеки "Microsoft Scripting Runtime" и нажмите кнопку "OK".
5. В меню "Вид" ("View") запустите команду "Просмотр объектов" ("Object Browser").
6. В выпадающем списке "Проект/библиотека" ("Project/Library") выберите библиотеку "Scripting".

Как я понял за номер листа отвечает .Worksheets(1), и для обработки всех листов нужно зациклить кусок, начиная с этой строки до Set objNonEmptyCells = Nothing, но а за что отвечает .Cells.SpecialCells(2)?

А vbs-скрипт прекрасно справляется с поставленной задачей, спасибо, Dmitrii!

Стремление - залог успеха

18 (изменено: Dmitrii, 2011-05-18 11:48:14)

Re: VBScript: Поиск и автозамена данных в .xls

Lucky пишет:

Нагуглил такую инструкцию...

Формулировку "Запустите одно из приложений MS Office" я бы заменил на такую: "Откройте предназначенный для обработки макросом документ в соответствующем приложении MS Office".
Все ссылки на компоненты и библиотеки относятся не к самому офисному приложению, а к VBA-проекту, который является частью документа (в данном случае - рабочей книги).

Lucky пишет:

... за номер листа отвечает .Worksheets(1)...

Да.

Lucky пишет:

... для обработки всех листов нужно зациклить кусок...

В кодах обоих вариантов сценария замените фрагмент с оператора On Error Resume Next по оператор objExcel.Quit (включительно) на такой фрагмент:

On Error Resume Next
For Each objWSh In objWB.Worksheets
    Set objNonEmptyCells = objWSh.Cells.SpecialCells(2)
    If Err.Number = 0 Then
        For Each objItem In objNonEmptyCells
            strTemp = objItem.Value
            For i = 0 To UBound(arrIDs)
                If InStr(strTemp, arrIDs(i)) > 0 Then
                    objItem.Value = Replace(strTemp, arrIDs(i), arrNames(i))
                    Exit For
                End If
            Next
        Next
        Set objNonEmptyCells = Nothing
    Else
        Err.Clear
    End If
Next
On Error GoTo 0
Erase arrIDs: Erase arrNames
objWB.Save
objWB.Close
Set objWB = Nothing
objExcel.Quit
WScript.Echo "Готово."
Lucky пишет:

... за что отвечает .Cells.SpecialCells(2)?

За выборку из всего множества ячеек рабочего листа тех ячеек, значением которых является константа.