Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 Курс Информатика VBA(ЗО) / Книги / В.Д.Хорев - Самоучитель программирования на VBA в Microsoft Office

.pdf
Скачиваний:
2702
Добавлен:
31.05.2015
Размер:
21.66 Mб
Скачать

Из документа Word в таблицу Excel 81

Усовершенствования действующей модели для создания макросаархивариуса Word-документов

Итак, действующая модель сделала свое дело, и было показано, каким образом документ Word может записать свои данные в таблицу Excel, не прибегая к помощи самого Excel. Чтобы этот механизм можно было использовать на практике, необходимо решить ряд проблем.

Первое: при каждом очередном вызове макроса, то есть при сохранении текущего документа Word, запись в таблицу должна производиться в очередную свободную строку. Это означает, что вместо 2 в выражениях вида .Cells(2, ...) необходимо использовать некоторую переменную, которая принимала бы последовательно возрастающие значения. Можно использовать специальную целочисленную переменную, назовем ее Count, при помощи которой можно было бы перебирать строки таблицы и останавливать этот процесс при обнаружении свободной строки. Конструкция цикла For ... Next уже была рассмотрена. Но здесь необходим оператор цикла другого вида:

Count = 1

While EX.ActiveSheet.Cells(Count, 1).Value <> ""

Count = Count + 1

Wend

Цикл While ... Wend выполняется до тех пор, пока помещенное в строку While логическое выражение возвращает значение True (Истина). То есть, пока выражение

EX.ActiveSheet.Cells(Count, 1).Value остается не равным пустой строке (""). Это оз-

начает, что переменная Count, начав свой отсчет с 1, будет увеличиваться на 1 до тех пор, пока в первом столбце текущего листа не встретится пустая ячейка. После этого можно использовать значение Count во всех тех местах, где необходимо указать номер строки, в которую производится запись — при каждом выполнении макроса это будет номер очередной свободной строки.

см. также в приложении раздел “Цикл While … Wend”.

Второе. Следующая проблема, которую необходимо решить, связана с выбором рабочего листа. В подготовленной книге Excel есть четыре листа, на которых макрос, согласно замыслу, должен помещать сведения о документе. В предыдущем примере обращение к рабочему листу было, как к ActiveSheet — какой бы лист ни был активным, с ним и будем работать. Активным после открытия книги будет тот лист, на котором она была закрыта. Пусть так все и остается, но только до первого обращения к активному листу нам следует сделать активным нужный нам лист книги. Немного упрощая задачу на первом этапе ее решения, предположим, что документы типа “договор”, “акт” и т.д. начинаются с соответствующих слов, то есть, “Договор”, “Акт” и т.д. Предположим также, что слова эти всегда написаны с прописной буквы и все остальные буквы слова — строчные. Нам требуется теперь проанализировать первое слово документа и принять решение, на какой лист его поместить. Если определить принадлежность документа не удалось, его следует отнести к “прочим” документам. С этого и начнем:

EX.Worksheets("Прочее").Activate

Теперь, если не будет принято никакого решения, активным останется лист “Прочее” и весь последующий код, где упоминается объект ActiveSheet, будет относиться именно к этому листу.

Анализ первого слова Word-документа

Третье. Далее следует проанализировать первое слово документа, и, если оно совпадет с “Договор”, “Акт” или “Доверенность”, сделать активным соответствующий лист.

Для решения этой задачи нам понадобится конструкция Select Case.

Select Case ActiveDocument.Words(1)

Case "Договор ": EX.Worksheets("Договор").Activate

82 Глава 3. Поверка гармонии Word алгеброй Excel

Case "Акт ": EX.Worksheets("Акт").Activate

Case "Доверенность ": EX.Worksheets("Доверенность").Activate

End Select

Здесь строка Select Case содержит выражение-переключатель, а в каждой из строк Case до двоеточия указана константа, с которой может совпасть значение переключателя, а после двоеточия — оператор, который необходимо в этом случае выполнить.

см. также в приложении раздел “Конструкция Select Case … End Select”.

Обратите внимание на пробелы в конце слов “Договор “, “Акт “ и “Доверенность “. В именах рабочих листов этих пробелов нет, но при анализе строки, возвращаемой семейством Words активного документа, они необходимы. С точки зрения объектной модели Word слово в большинстве случаев — это слово плюс пробел после него.

Теперь документ, начинающийся, например, со слова “Доверенность”, будет зарегистрирован на листе “Доверенность”. Чтобы убедиться в этом, следует ввести новую редакцию текста макроса

— см. листинг 3.2.

ЛИСТИНГ 3.2

Sub FileSave()

ActiveDocument.Save

Dim EX As Excel.Workbook

Dim Count As Integer

Set EX = GetObject("C:\DocTable.xls")

EX.Worksheets("Прочее").Activate

Select Case ActiveDocument.Words(1)

Case "Договор ": EX.Worksheets("Договор").Activate

Case "Акт ": EX.Worksheets("Акт").Activate

Case "Доверенность ": EX.Worksheets("Доверенность").Activate

End Select

Count = 1

While EX.ActiveSheet.Cells(Count, 1).Value <> ""

Count = Count + 1

Wend

With EX.ActiveSheet

.Cells(Count, 3).Value = _ ActiveDocument.Range(0, 200).Text

.Cells(Count, 2).Value = _ ActiveDocument.Paragraphs(1).Range.Text

.Hyperlinks.Add _

.Cells(Count, 1), ActiveDocument.FullName

End With

EX.NewWindow

EX.Save

Set EX = Nothing

End Sub

Из документа Word в таблицу Excel 83

Откроем теперь в окне Word произвольный документ, начинающийся со слова “Доверенность” (рис. 3.8) и сохраним его любым способом. Затем достаточно заглянуть в рабочую книгу DocTable, чтобы убедиться, что документ зарегистрирован на нужном листе (см. рис. 3.9).

Рис. 3.8. В окне Word открыт документ, начинающийся со слова “Доверенность“

Рис. 3.9. Документ зарегистрирован на листе, имя которого совпадает с первым словом документа

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

Выше уже отмечалось, что 200 символов текста будут помещены в ячейку третьего столбца для того, чтобы можно было искать документы по вхождению строки. Например, если нас интересует договор с определенной фирмой или доверенность на имя определенного человека или просто документ за каким-то номером, то можно найти нужную строку в таблице при помощи функций поиска Excel, и открыть посредством гиперссылки требуемый документ. Но вот вопрос, сколько символов текста из документа помещать в таблицу? Если системные ресурсы не накладывают сколько-нибудь существенных ограничений, то ничто не мешает помещать в ячейку весь текст документа. Однако существуют ограничения в самой рабочей книге Excel. В версиях MS Office младше 97 в ячейку листа можно поместить не более 255 символов. Начиная с Office 97 это значение увеличено до более, чем 32 тысяч символов. Но все равно может встретиться документ, содержащий столько символов, сколько не поместится в ячейку таблицы. Кроме того, автоматическое копирование в таблицу больших текстов (а их тоже иногда приходится сохранять в окне Word) может привести к неоправданному расходованию ресурсов. С другой стороны, если задаться числом символов, допустим 1000, то может встретиться документ, содержащий менее, чем 1000 символов текста и тогда при выполнении макроса возникнет ошибка выполнения. Чтобы избежать подобных осложнений, можно сделать число сохраняемых символов переменным. В разделе объявления переменных (в начале исходного текста) опишем еще одну, целочисленную переменную, значение которой будет определять число сохраняемых символов текста:

Dim MaxChars As Integer

Затем присвоим ей одно из двух значений:

84 Глава 3. Поверка гармонии Word алгеброй Excel

If ActiveDocument.Characters.Count < 1000 Then

MaxChars = ActiveDocument.Characters.Count

Else

MaxChars = 1000

End If

Если документ содержит менее 1000 символов, то MaxChars будет равняться числу символов в документе — именно эту величину возвращает свойство Count семейства Characters

активного документа ActiveDocument. В противном случае MaxChars = 1000.

Далее остается отредактировать фрагмент кода, в котором задается число копируемых символов:

With EX.ActiveSheet

.Cells(Count, 3).Value = _ ActiveDocument.Range(0, MaxChars).Text

...

End With

Макрос-архивариус анализирует содержимое Wordдокумента

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

Постановка задачи

Разумеется, если речь идет об абсолютно произвольном документе, то задача его анализа не имеет 100%-го решения, по крайней мере, средствами VBA. Возможно, впрочем, что даже технологии искусственного интеллекта здесь не помогли бы. Но не полный семантический анализ не требуется — все, что хотелось бы, это каким-то образом найти в тексте ключевые реквизиты — такие, как даты, номера, имена людей и названия организаций. Тут же, попутно, неплохо было бы распознать вид документа, чтобы поместить его на нужный лист рабочей книги. Метод распознавания по первому слову, использованный в предыдущем примере, конечно, слишком примитивен.

Чтобы реализовать простейший анализ документа, необходимо “просмотреть” его текст слово за словом. Это нетрудно сделать — в свойстве Words документа содержится семейство всех его слов, к которым можно обращаться по номерам. Например, выражение ActiveDocument.Words(1) вернет первое слово текущего документа. А в свойстве Count этого же семейства содержится количество слов в документе. Понятно теперь, как можно при помощи цикла For “просмотреть” все слова документа. Конечно, переменная цикла N должна быть предварительно объявлена:

For N = 1 To ActiveDocument.Words.Count

... ActiveDocument.Words(N) ...

Next N

Обращаясь внутри этого цикла к членам семейства Words по индексу N, можно получить доступ последовательно ко всем словам документа. Под словом в документе Word понимается группа символов, отделенная пробелом или знаком препинания, причем знак препинания является самостоятельным словом, а пробел относится к идущему перед ним слову.

Из документа Word в таблицу Excel 85

Но есть ли смысл в просмотре всех слов документа? Скорее всего, все важнейшие реквизиты сосредоточены в его начале. Кроме того, если макросу вдруг встретится документ большого размера, просмотр всех слов может стать довольно длительной операцией. Поэтому остановимся на просмотре первых, например, 100 слов документа. Для случая, когда документ состоит менее, чем из 100 слов, используем переменную WordCount:

WordCount = ActiveDocument.Words.Count

If WordCount > 100 Then WordCount = 100

For N = 1 To WordCount

... ActiveDocument.Words(N) ...

Next N

Теперь, если в документе более ста слов, анализироваться будут первые 100, а в противном случае — все слова документа.

Реализация механизма анализа содержимого Word-документа

В чем же будет заключаться анализ и каковы должны быть его результаты? Результатом будет строка описания документа, в которую должны быть включены важнейшие, идентифицирующие документ слова. Поместив затем эту строку в ячейку Excel-таблицы, можно получить средство ориентации в документной базе данных.

Будем “собирать” строку описания в переменной S, которую необходимо объявить типа

String:

Dim S As String

см. в приложении подраздел “String” в разделе “Типы данных”.

Мы можем добавлять к ней выбранные слова при помощи оператора присваивания:

S = S + ...

В результате строка S “накопит” в себе описание документа.

см. также в приложении раздел “Операции со строками”.

Поскольку, с одной стороны, первое слово документа все же неплохо его характеризует, а с другой — нам необходимо начинать просмотр слов не с первого, а со второго (по причинам, которые станут понятными позднее), следует без всяких условий поместить в S первое слово документа:

S = ActiveDocument.Words(1)

Казалось бы, на тот маловероятный, но все же возможный случай, когда сохраняемый документ не содержит ни одного слова, эту операцию следует обусловить значением переменной

WordCount, иначе может возникнуть ошибка выполнения:

If WordCount > 1 Then S = S + ActiveDocument.Words(1)

На самом деле, по меньшей мере, одно слово содержится даже в пустом документе — непечатаемый символ абзаца, который с точки зрения объектной модели Word также является словом.

Наконец, чтобы внутри оператора цикла For не упоминать каждый раз объект

ActiveDocument, добавим конструкцию With…End With:

WordCount = ActiveDocument.Words.Count

86 Глава 3. Поверка гармонии Word алгеброй Excel

If WordCount > 100 Then WordCount = 100

S = ActiveDocument.Words(1)

With ActiveDocument

For N = 2 To WordCount

... .Words(N) ...

Next N

End With

Теперь все слова внутри цикла For, начинающиеся с точки (например, .Words(N)), будут

подразумевать отношение к объекту ActiveDocument, то есть к активному документу.

Итак, все готово для проведения собственно анализа. Остается наполнить “скелет” конструкции анализатора программным кодом, который выбирал бы среди встречающихся слов наиболее важные с тем, чтобы запомнить их в строке описания документа. Как и по какому принципу выбирать слова? Тут возможны различные подходы. Какой из них выбрать — зависит в значительной степени от предметной области, к которой относятся рассматриваемые документы. Постараемся продемонстрировать общие принципы, на основе которых (как надеется автор) каждый сможет сформировать собственный анализатор.

Итак, существует два основных класса возможностей. Можно выбирать слова, основываясь на их значении, или же ориентироваться на признаки форматирования слова.

Анализ значений слов в документе Word

Проиллюстрируем вначале первый подход. В предыдущем варианте макроса при помощи конструкции Select Case уже сравнивалось первое слово документа с несколькими строковыми значениями (см. раздел “Анализ первого слова Word-документа”). Тогда, было специально оговорено, что сравниваемое слово должно состоять из строчных букв, а начинаться с прописной буквы.

Постановка задачи

Конечно, в реальных документах слова могут быть написаны абсолютно произвольным образом. Чтобы решить эту проблему, нам потребуется помощь функции UCase. Получив строку, эта функция возвращает ту же строку, где все буквы — прописные. Если сравнивать возвращенное функцией UCase значение со строкой из прописных букв, то нет разницы, из каких букв состояло исходное слово — сравнение в любом случае будет корректным. Иными словами, выражение

UCase(ActiveDocument.Words(N))

вернет слово “ДОГОВОР” вне зависимости от того, из каких букв состояло N-е слово в текущем документе: “Договор”, “ДОГОВОР” или “дОгоВОр”.

см. также в приложении раздел “Преобразования регистра (функции LCase, UCase)”.

Ранее уже упоминался тот факт, что, если слово в документе сопровождается пробелом, семейство Words возвращает слово вместе с пробелом. Если же пробела после слова нет, то, естественно, Words(N) вернет N-е слово без пробела. Чтобы избежать разночтений в этом вопросе, применим функцию Trim. Эта функция просто удаляет пробелы перед и после переданной ей строки. Таким образом, если сравнивать значение выражения

UCase(Trim(ActiveDocument.Words(N)))

со строковым значением, например, “ДОГОВОР”, то никакие пробелы или различия между строковыми и прописными буквами не помешают.

Из документа Word в таблицу Excel 87

см. также в приложении раздел “Функции удаления пробелов (LTrim, RTrim, Trim)”.

Анализ слова Word-документа

Итак, попробуем проанализировать очередное слово посредством конструкции Select

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

Select Case UCase(Trim(ActiveDocument.Words(N)))

Case "№", "#", "N": _

S = S + "№" + ActiveDocument.Words(N + 1)

Case "ДОГОВОР": _

EX.Worksheets("Договор").Activate

Case "ДОВЕРЕННОСТЬ": _

EX.Worksheets("Доверенность").Activate

Case "АКТ": _

EX.Worksheets("Акт").Activate

End Select

ПРИМЕЧАНИЕ

Напомним, что сочетание пробела со знаком подчеркивания ( _) означает перенос на следующую строку. Редактор Visual Basic “понимает” разделенные такими символами строки как одну строку. Необходимость переноса возникает при размещении текста на книжной странице. Необходимо учитывать при этом, что редактор Visual Basic позволяет ввести сколь угодно длинную строку, и на самом деле необходимости в таких переносах нет.

Строка

Case "№", "#", "N": _

S = S + "№" + ActiveDocument.Words(N + 1)

иллюстрирует возможный способ анализа. Если очередное (N-е) слово представляет собой один из “номерных” символов ("№", "#" или "N"), то следующее после него (то есть, N+1-е слово) поместим в строку описания — поскольку это, скорее всего, и есть номер документа. Если же очередным словом оказывается, например, “ДОГОВОР”, то нужно просто сделать активным соответствующий лист рабочей книги. Заметим, в данном операторе остается возможность для ошибки выполнения, если в документе меньше 100 слов и последнее, N-е слово представляет собой “номерной” символ, то произойдет обращение к несуществующему N+1-му слову!

ПРИМЕЧАНИЕ

Анализ, основанный на значении слова, может принимать разнообразные формы. Можно обращаться к последующему (N+1) или предыдущему (N-1) словам. Чтобы извлечь из документа и поместить в строку-накопитель не единственное слово, а последовательность слов, необходимо использовать свойства объекта Range — текстового диапазона. Например, для помещения в строку

S непрерывного текстового фрагмента можно использовать оператор вида:

S=S + ActiveDocument.Range(Начальный_символ, Конечный_символ)

В скобках необходимо задать каким-нибудь образом ссылки на начало и конец текстового диапазона. Например, можно просто явным образом указывать конкретный символ конкретного слова — ActiveDocument.Words(N).Characters(M). Если нужно включать слова цели-

ком, то следует использовать свойства Start и End. Эти свойства представляют собой ссылки на первый и последний символы слова. Например, выражение

ActiveDocument.Range(ActiveDocument.Words(N).Start, _

88 Глава 3. Поверка гармонии Word алгеброй Excel

ActiveDocument.Words(N + 10).End)

вернет текстовый фрагмент, заключающий в себе 11 слов, начиная с N-го. При расчете подобных ссылок следует помнить о том факте, что знаки препинания и непечатаемый символ абзаца считаются отдельными словами.

Конструкция оператора Case допускает проверку множества вариантов для каждой ветви выбора. Вот как можно было бы, например, извлечь из текста дату в формате “ДД месяц ГГГГ”:

With ActiveDocument

...

Select Case UCase(Trim(.Words(N)))

Case "ЯНВАРЯ", "ФЕВРАЛЯ", "МАРТА", "АПРЕЛЯ", _ "МАЯ", "ИЮНЯ", "ИЮЛЯ", "АВГУСТА", _ "СЕНТЯБРЯ", "ОКТЯБРЯ", "НОЯБРЯ", _ "ДЕКАБРЯ": S = S + _

ActiveDocument.Range(.Words(N - 1).Start, _

.Words(N + 1).End)

...

End Select

...

End With

Если, например, очередным (N-м) словом окажется слово “октября”, то в строку S попадут три слова — слово перед словом “октября”, само слово “октября” и слово после “октября”.

Посимвольный анализ слов в документе Word

Ничто не мешает нам одновременно применить другой подход к анализу документа в пределах все того же цикла For, пока выражение .Words(N) все еще содержит очередное слово документа.

Постановка задачи

Можно было бы, например, выбирать слова, выделенные жирным шрифтом или курсивом. Для этого необходимо обратиться к свойствам отдельного символа слова. Символы каждого слова в документе представлены его свойством Characters. Например, первый символ N-го слова за-

ключен в объекте ActiveDocument.Words(N).Characters(1). За признаки начертания

полужирный и курсив отвечают соответственно свойства символа Bold и Italic — эти свойства возвращают логические значения True (Истина) или False (Ложь). Поэтому в условном операторе

If нет необходимости с чем-либо сравнивать эти значения. Если символ, например, выделен полужирным шрифтом, то его свойство Bold вернет значение True.

Применение логической операции Or (логическое ИЛИ)

If .Words(N).Characters(1).Bold _ Or _

.Words(N).Characters(1).Italic _

Then

S = S + .Words(N)

End If

Здесь условная конструкция немного усложнена по сравнению с теми, которые были рассмотрены ранее. Строка If… превратилась здесь в три строки, причем первая и третья содержат два независимых условия, объединенных логической операцией Or (логическое ИЛИ). Если первый

Из документа Word в таблицу Excel 89

символ анализируемого слова выделен полужирным ИЛИ курсивом, то все слово будет добавлено в строку описания.

см. также в приложении раздел “Логические операции”.

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

Применение логической операции And (логическое И)

Чтобы определить, является ли символ прописной буквой, достаточно прочитать значение его свойства Case. Если в нем содержится константа wdUpperCase, значит, символ является прописной буквой.

If .Words(N).Characters(1).Case = wdUpperCase _ And _

.Words(N - 1) <> "." _ And _

.Words(N - 1) <> Chr(13) _

Then

S = S + .Words(N)

End If

Здесь в одном операторе If объединены три логических условия, причем объединяет их на этот раз логическая операция And (логическое И). Второе и третье условия касаются предыдущего, то есть N-1-го слова — это слово должно НЕ являться знаком препинания “точка” И (то есть, одновременно с этим) НЕ являться непечатаемым символом конца абзаца Chr(13), чтобы все выражение вернуло логическое значение Истина. Только при выполнении всех трех условий слово будет добавлено в строку описания. Благодаря этому большинство слов в начале предложений будет проигнорировано, несмотря на первую прописную букву и в строку описания попадут, в основном, имена собственные. Кстати сказать, именно ради этого оператора начинался отсчет со второго, а не с первого слова — в противном случае пришлось бы усложнить эту и без того сложную конструкцию еще одним условным оператором (условием).

см. также в приложении раздел “Логические операции”.

Наконец, хорошо бы “выловить” в тексте все слова, начинающиеся с цифры, — как правило, с цифры начинаются такие реквизиты, как номера, суммы и даты, которые очень хорошо характеризуют документ и зачастую однозначно его идентифицируют.

If .Words(N).Characters(1) >= "0" _ And _

.Words(N).Characters(1) <= "9" _

Then

S = S + .Words(N)

End If

Для проверки “на цифру” используем два условия: символ больше или равен “0”, и одновременно он меньше или равен “9”.

Итак, наш анализатор готов в первом приближении. Можно теперь поместить все реализованные способы анализа в тело цикла For и внести необходимые коррективы в исходный текст макроса.

Управление ошибками выполнения макроса

Кроме всего вышеописанного следует добавить в начало текста еще один оператор:

On Error Resume Next

90 Глава 3. Поверка гармонии Word алгеброй Excel

Операторы On Error управляют реакцией макроса на ошибки выполнения. В частности, On Error Resume Next определяет, что при возникновении ошибки в процессе выполнения некоторого оператора работа программы должна возобновиться со следующего оператора. Эта строчка необходима на тот случай, если при анализе очередного слова возникнет какая-то непредвиденная ситуация. На одну из таких возможных ошибочных ситуаций уже было указано ранее. Чтобы не пугать ничего не подозревающего пользователя, который всего лишь сохраняет документ, появлением диалогового окна с сообщением об ошибке выполнения и окна редактора Visual Basic, пожертвуем качеством анализа. В конце концов, данная строка описания документа не слишком много потеряет от отсутствия одного из слов.

В результате должна получиться процедура представленная на листинге 3.3.

ЛИСТИНГ 3.3

Sub FileSave()

ActiveDocument.Save

On Error Resume Next

Dim EX As Excel.Workbook

Dim Count, MaxChars As Integer

Dim N, WordCount As Integer

Dim S As String

Set EX = GetObject("C:\DocTable.xls")

EX.Worksheets("Прочее").Activate

WordCount = ActiveDocument.Words.Count

If WordCount > 100 Then WordCount = 100

S = ActiveDocument.Words(1)

With ActiveDocument

For N = 2 To WordCount

Select Case UCase(Trim(.Words(N)))

Case "№", "#", "N": _

S = S + "№" + .Words(N + 1)

Case "ДОГОВОР": _

EX.Worksheets("Договор").Activate

Case "ДОВЕРЕННОСТЬ": _

EX.Worksheets("Доверенность").Activate

Case "АКТ": _

EX.Worksheets("Акт").Activate

End Select

If .Words(N).Characters(1).Case = wdUpperCase _ And _

.Words(N - 1) <> "." _ And _

.Words(N - 1) <> Chr(13) _

Then

S = S + .Words(N)

Соседние файлы в папке Книги