Главная > Powershell > Поиск текста в MS Word с помощью Powershell

Поиск текста в MS Word с помощью Powershell

Идея написания этой статьи появилась после того, как один мой знакомый начинающий тестировщик (или тестер, не знаю как правильнее) с восхищением рассказывал, как видел у своего более опытного коллеги скрипт для тестирования документации. Если я не ошибаюсь, то тестирование документации это поиск неточностей, двусмысленностей  неоднозначностей и всякого такого в документации к продукту. Например, не должно быть фраз вроде «Эта кнопка должна быть квадратной, прямоугольной или др. форм», «Этот текст может быть красным, жёлтым и т.д.». Т.е. не должно быть фраз типа и т.д., и т.п., и пр., и так далее.

Собственно как я понял скрипт только то и делал, что искал в .doc-файлах такие слова (точнее, наверное, будет сказать фразы) и если находил, то сообщал об этом. В первую минуту подумалось, а смысл такого скрипта – Ctrl+F и ищи себе на здоровье, но подумав, решил, что всё-таки быстрее будет «скормить» такому скрипту файл, который сам всё найдёт, чем открывать файл, нажимать на поиск, вбивать искомую фразу. Особенно, если учесть, что искать нужно не одну фразу, а несколько (и т.д., и т.п., и пр.). А так как одна и та же одна фраза с помощью пробелов может «превратиться» в несколько (например, «и т.д.», «и т. д.», «и тд.» для поиска совершенно разные фразы (не считая первых трёх символов)), то искать так можно очень долго и польза от такого скрипта налицо.

Не долго думая решил написать свой собственный скрипт поиска нескольких слов (фраз) в тексте.

Итак, поехали!

MS Word (как и остальные продукты MS Office, как и Internet Explorer, IIS и многие другие продукты) предоставляет доступ к своим службам через COM-объекты. Я не буду вдаваться в подробности, что такое COM-объекты, об этом можно почитать на бескрайних просторах интернета (например, в википедии).

Для того чтобы работать с документом Word его необходимо сначала открыть (или создать, если речь идёт о новом документе).

Для тестовых целей я взял файл, в который кидаю разные заметки о Powershell:

$File="D:\Powershell\Powershell.doc"

Искать я (также в тестовых целях) буду два слова, которые точно есть и одну фразу, которой нет:

$Find_String="power", "shell", "нет такой фразы"

Создаём объект Word:

$word = New-Object -ComObject word.application

С помощью метода Open коллекции Documents открываем наш файл, сохраняя ссылку на него в переменной $doc:

$doc = $word.documents.open($File)

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

$word | Get-Member

Далее в переменную $sel заносим  ссылку на объект Selection:

$sel = $word.selection

Объект Selection представляет текущий выделенный фрагмент. Выполняя какую-либо операцию Word’е (например меняя шрифт), мы выделяем соответствующий текст и применем к нему новый параметр форматирования. Объект Selection всегда присутствует в документе; если ничего не выделено, этот объект представляет курсор ввода.

Если есть желание (или в тестовых целях) можно показать наш документ, чтобы посмотреть как Powershell лазит по документу, и то ли он ищет:

$word.visible = $true

Для поиска текста воспользуемся объектом Find – членом объекта Selection. Объект Find имеет свои свойства и методы (все их можно посмотреть с помощью Get-Member), нам из них интересны только свойство Text, в котором задаётся искомый, текст и метод Execute(), выполняющий сам поиск:

$sel.Find.Text = $find 
$sel.Find.Execute()

Зациклив вызов метода Execute() по массиву, содержащему объекты для поиска, можно искать сколько угодно слов и фраз.

foreach ($find in $Find_String)
{
     ...
     $sel.Find.Text = $find
     $sel.Find.Execute()
     ...
}

Метод Execute() выполняется до первого вхождения слова (фразы) в документ. Поэтому, если просто нужно только убедиться в наличии текста в документе, можно ограничиться одиночным вызовом Execute():

if ($sel.Find.Execute())
{
    "$find найден"
}

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

Для этого можно воспользоваться свойством Found объекта Find, которое возвращает True каждый раз, когда обнаруживается искомый элемент, и циклом с постусловием:

do
{
    if ($sel.Find.Execute())
    {
        $count++
        # Start-Sleep -Seconds 2
    }
}
while ($sel.Find.Found)

Указанные критерии поиска применяются только к выделенному в данный момент тексту. Однако, если Selection включает лишь курсор ввода, то поиск ведется по всему документу. Когда обнаруживается элемент, удовлетворяющий критериям поиска, он автоматически выделяется подсветкой и становится текущим выделенным фрагментом. Раскомментировав закомментированную (вот такая вот тавтология) задержку в 2 секунды, можно убедиться, что текст находится и находится именно то, что нужно.

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

$sel.Font.Bold = $true
$sel.Font.Size = 16

При этом нужно будет не забыть сохранить документ перед закрытием:

$doc.Save()

После того, как поиск окончен выводим сколько и чего нашли:

if ($count)
{
    "$find найдено $count раз"
}

После окончания первого прохода курсор будет находиться в конце документа, и чтобы повторить поиск нужно его вернуть в начало документа. Вообще для этого у объекта Selection есть специальный объект HomeKey(). Но мне с ним подружиться пока не удалось, поэтому среди свойств объекта Selection я обнаружил метод GoTo(). Поэкспериментировав с его аргументом были замечены интересные вещи, например, вызвав GoTo(), с аргументом 1 (GoTo(1)) происходит переход на следующую страницу, GoTo(3) – переход на следующую строку, ну а GoTo(0)– переход в начало документа. Однако, такой способ наверное не совсем корректен, так как при вызове GoTo(0) на экран выводится куча ненужной информации, поэтому пришлось перенаправить её в NULL:

$sel.GoTo(0) | Out-Null

После этого осталось только закрыть наш Word:

$word.Quit()

Вот и всё.

P. S.

Запустив готовый скрипт, я был немного удивлён, так как ожидал, что слова «power» и «shell» будут в одинаковом количестве, однако

power найдено 34 раз

shell найдено
42 раз

Недоумевая начал внимательно рассматривать свой файл «вручную». Найдя несколько слов об объекте WScript.Shell (о котором тоже как-нибудь поговорим) успокоился 🙂 и решил для верности к объектам поиска добавить ещё и слово «powershell» – по идее их должно было быть столько же, сколько и «power».

На этот раз я был доволен:

power найдено 34 раз

shell найдено
42 раз

powershell найдено
34 раз

Таким не очень хитрым способом можно определять наличие слов в .doc-файлах и/или подсчитывать количество определённых слов.

Реклама
Рубрики:Powershell Метки: , ,
  1. powershell
    05/09/2012 в 22:17

    Класс. А можно найти определённое слово в целой папке с документами word?
    Есть документы с грифом КОНФИДЕНЦИАЛЬНО. Надо как-то перебором это делать наверно. Получается надо создавать для каждого документа новый объект $word = New-Object -ComObject word.application?

  2. 06/09/2012 в 09:24

    Конечно, можно! Думаю будет проще, если сам Word открыть один раз, а в цикле уже перебирать документы, т.е. так: создали объект Word, в цикле перебрали все документы и когда вышли из цикла закрыли Word.

  3. 13/04/2013 в 08:42

    Hi, I check your new stuff like every week. Your writing style is awesome, keep it up!

  4. 25/04/2013 в 00:57

    It’s going to be ending of mine day, except before ending I am reading this fantastic paragraph to improve my experience.

  5. 27/04/2013 в 21:45

    Having read this I believed it was very enlightening. I
    appreciate you spending some time and energy to put this article together.
    I once again find myself spending a lot of time both reading and
    posting comments. But so what, it was still worthwhile!

  6. 28/04/2013 в 20:14

    I was suggested this blog by my cousin. I’m not sure whether this post is written by him as no one else know such detailed about my difficulty. You’re wonderful!
    Thanks!

  7. 29/04/2013 в 15:01

    I am really thankful to the holder of this web site who has shared this fantastic piece of writing at at this time.

  8. 27/04/2016 в 09:16

    А как можно заменить найденный текст на значения переменных, вместо изменения шрифта?

  1. 19/05/2011 в 12:34
  2. 23/01/2013 в 11:46
  3. 30/01/2015 в 19:15
    URL

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: