Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Программирование, связанное с MS Office > Макрос для исправления слитых переносов


Автор: Guest45 15.6.2015, 23:52
Собственно, задача:

Имеется текст в коде ASCII, в котором перенесенные слова слиты, так что значок переноса оказывается посреди слова.
А поскольку это .txt и форматирующей структуры нет, то такие переносы ничем не отличаются от минусов и тире.
Ручная правка исключается - файл довольно велик, Ворд находит несколько тыс. сочетаний буква-дефис-буква.
Непосредственно удалить их нельзя, так как пострадают нормальные слова, пишущиеся через дефис, их в русском языке довольно много.
Необходимо написать макрос для Ворда (пригодный начиная от Офиса-2000).

Идея состоит в следующем:
Берем слово в строковую переменную, исключаем дефис и результат сличаем со словарем Ворда.
Если орфоконтроль не находит ошибки, вносим исправленное слово в текст.
Если слово без дефиса опознается как ошибочное, выбрасываем результат, оставляем в тексте как есть.

В чем прошу помощь.
Я неплохо знаю бейсики, в т.ч. VB6, но VBA включает некоторые специфические команды, по которым и прошу подсказки.
Итак:

1) Как взять в строковую переменную очередное слово из текста?

2) Как проверить содержимое строковой переменной при помощи системы орфографии Ворда?
(Достаточно получить булевское значение: верно слово, или нет.)

3) Как заменить слово в тексте на содержимое строковой переменной?

Прошу примеры написания этих команд в теле макроса.  user posted image

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

Автор: Akina 16.6.2015, 09:16
Код

Dim oneWord As Range, Result As Boolean

For Each oneWord In ThisDocument.Words
  Result = Application.CheckSpelling(oneWord)
  If Not Result Then
    If Trim(oneWord.Text) <> "Replaced" Then
      oneWord.Text = "Replaced "
    End If
  End If
Next




Автор: Guest45 16.6.2015, 18:37
Такая конструкция цикла мной еще не использовалась.

Сделал проверочный .txt размером в два абзаца, открыл Вордом-2000.
Сделал макрос, скопипастил в него ваш пример как есть.
Запустил.
Макрос быстро провернулся, никаких изменений в тексте не произвел.

Тогда заремил строку с орфографической проверкой и последующий IF по Result,
оставил в цикле только второй (вложенный) IF.
Предположив, что теперь все слова проверочного текста должны быть заменены словом Replaced .
Запустил.
Никаких изменений текста.

Заремил и второй IF, оставил в цикле только строчку
oneWord.Text = "Replaced "

Запустил.
Макрос завис.
Вот это непонятно почему - ведь область не изменялась;
по достижении конца текста цикл должен был остановиться независимо - изменялись ли слова, или нет.

Растолкуйте результаты, плиз.



Автор: Akina 16.6.2015, 18:48
Цитата(Guest45 @  16.6.2015,  19:37 Найти цитируемый пост)
заремил 

 smile Нахуа? smile 
Ну чё на кофейной гуще-то гадать? Пройдите в режиме трассировки и посмотрите, как изменяются значения переменных. Заодно не поленитесь в текст добавить пару заведомо несуществующих слов - для контраста...

Автор: Guest45 16.6.2015, 18:59
Разумеется, в тексте преднамеренные ошибки есть.

Цитата(Akina @ 16.6.2015,  18:48)
Цитата(Guest45 @  16.6.2015,  19:37 Найти цитируемый пост)
заремил 

 smile Нахуа? smile 
 Чтобы на первых порах отстроиться от вопросов к грамматике.
Отладка "поблочно". Надо же начинать с простейшего. Но и оно не получилось пока.

А oneWord.Text это что? - указатель на слово в тексте?


дополнено:
Итак, проверку грамматики пока заремил, оставил только вложенный IF.

Поставил точку останова на     If Trim(oneWord.Text) <> "Replaced" Then
Посмотрел, что oneWord.Text в ней имеет значение квадратик в кавычках. (Кодов меньше 20h в тексте нет, кроме 0Dh, 0Ah. Проверено в HEX-просмотре FAR-ом.)

После продолжения макрос снова на эту точку не попадает, то есть цикл после одного прохода завершается.



Автор: Akina 16.6.2015, 22:55
В тексте нет преднамеренных ошибок. Более того - поскольку я не юзаю эти функции ежедневно, я написАл кейс и проверил, что он работает правильно. Приведённый код - копипаст РАБОЧИЙ ПРОВЕРЕННЫЙ. Среда - Ворд 2007.  И если у тебя он сбоит, я скорее поверю в избыточную кривизну твоих рук, уж извини...

Автор: Guest45 17.6.2015, 16:21
преднамеренно ошибки были мной вставлены в проверочный текст, который скармливался макросу smile

Пример, сорь, пока не работает почему-то.  Про кривизну рук - допускаю конечно, но Ctrl-C, Ctrl-V,  тут как бы кривить-то особено и не в чем...
Ворд работает, не глючит, претензий не было. Система - XP SP2, rus, но вроде на язык высокого уровня влиять не должна?
Помогайте кто может.

Автор: Akina 17.6.2015, 16:37
Guest45, давай так. Выкладывай файл до запуска макроса и после. Я у себя обработаю тот же файл. Сравним. Укажи сразу, что не нравится - если воспроизведётся, постараюсь понять, где собака порылась.

Автор: Guest45 17.6.2015, 17:17
Проверочный текст в смысле? - без проблем, прицепляю ниже. Но он один и тот же, ни одного изменения макросом не вносится.
Я подозреваю, что макрос по нему вообще не пробегает - уже писал выше, что цикл почему-то заканчивается после первого же прохода.

Автор: Akina 18.6.2015, 08:50
Воспроизводим по шагам.
1) Запустить Word.
2) Открыть - text.txt
3) Разработчик - Макросы
4) Имя = MyReplace
5) Создать
6) Вставляем приведённый выше код
7) Закрываем окно VBA
8) Разработчик - Макросы
9) MyReplace - Выполнить 
После выполнения этих операций я вижу в тексте слово "Replaced" в количестве 6 штук.

Добавлено через 2 минуты и 42 секунды
Как вариант, вместо шагов 3-5:
3) Открыть редактор VBA
4) Вставить - модуль
5) Вставить вышеприведённый код, обрамив его в Private Sub MyReplace() ... End Sub

Автор: Guest45 18.6.2015, 14:55
Отчет о проделанной работе:

1. Открываю проверочный текст Вордом.
(В окне Ворда - проверочный текст.)

2. Меню Сервис / Макрос / Макросы

3. Копипаст имени MyReplace

4. Создать.

5. Копипаст кода

Результат:
Код

Sub MyReplace()
'
' MyReplace Макрос
' Макрос создан18.06.2015
'

Dim oneWord As Range, Result As Boolean

For Each oneWord In ThisDocument.Words
  Result = Application.CheckSpelling(oneWord)
  If Not Result Then
    If Trim(oneWord.Text) <> "Replaced" Then
      oneWord.Text = "Replaced "
    End If
  End If
Next

End Sub


6. Закрыл окно VBA.

7.  Сервис / Макрос / Макросы

8. Выбор MyReplace

9. Выполнить.

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

Вариант 2
Сервис / Макрос / Редактор Visual Basic

Insert / Module
открывается чистое окно нового модуля

Создаю в нем следующий код:
Код

Private Sub MyReplace() 
Dim oneWord As Range, Result As Boolean

For Each oneWord In ThisDocument.Words
  Result = Application.CheckSpelling(oneWord)
  If Not Result Then
    If Trim(oneWord.Text) <> "Replaced" Then
      oneWord.Text = "Replaced "
    End If
  End If
Next
End Sub


Запускаю из меню VBA: кнопка Run
В тексте появились замененные слова Replaced.

Итак, второй вариант работает, а первый почему-то нет. 

Поэксериментирую со вторым, о результатах отпишусь.
Сенкс!



Примечание.
Вначале (т.е. вчера) и макрос запускал кнопкой Run не закрывая VBA, но макрос и таким запуском не работал.

Автор: Guest45 18.6.2015, 15:26
Кажется я выяснил, в чем отличие.
Модуль создается в разделе Project,
а макрос - в разделе Normal (по умолчанию "из Активных шаблонов")
Когда переключил на создание макроса из "Документ1", тогда он создался в разделе Project и заработал.

Хотя, записанные нажатия клавиш и т.п., создаются тоже в разделе Normal, но при этом работают.
Подозреваю, что не будет работать чтение - видимо тогда макрос вместо текста из окна пытается читать файл Normal.dot .

Спасибо за помощь!
Остальное, я надеюсь, самостоятельно докручу.

Автор: Akina 18.6.2015, 17:42
Цитата(Guest45 @  18.6.2015,  16:26 Найти цитируемый пост)
Когда переключил на создание макроса из "Документ1", тогда он создался в разделе Project и заработал.

Теперь понятен источник твоих проблем. При создании кода в normal.dot итератор ThisDocument.Words перебирал, как это не странно, почему-то слова именно из Normal.dot.
И кто мешал это увидеть сразу, при трассировке?

Автор: Guest45 18.6.2015, 18:26
Не показывалось это, или я не знал, где посмотреть. Пришлось догадкой доходить)))))


Версия "альфа" макроса для удаления слившихся переносов будет выглядеть вот так:
Код

Sub UnDivision()
'
' UnDivision Макрос
' Удаление слитых переносов
'
Dim oneWord As Range, i As Long

If MsgBox("Этот макрос удалит слитые переносы из текста" + vbCrLf + "   Лицензия: бесплатно." + vbCrLf + "Авторские права: forum.vingrad.ru", 1) = 2 Then Exit Sub

i = 0: Word1$ = "": Word2$ = ""
For Each oneWord In ThisDocument.Words
  Word3$ = oneWord.Text
  If Word2$ = "-" And Trim(Word1$) <> "" And Right$(Word1$, 1) <> " " Then
    Word3$ = Trim(Word1$) + Trim(Word3$)
    For j = 1 To Len(Word3$)
      If Asc(Mid$(Word3$, j, 1)) < 192 Then
        Word3$ = "неправитьцифры"
        Exit For
      End If
    Next j
    If Application.CheckSpelling(Word3$, , 0) = True Then
      ThisDocument.Words(i) = ""
      i = i - 2
    End If
  End If
  i = i + 1
  Word1$ = Word2$
  Word2$ = Word3$
Next

End Sub


Полностью еще не обкатана, возможны какие-нибудь глюки, но пока у меня сработало нормально.

Гран мерси за оказанную помощь!



Автор: Akina 19.6.2015, 08:42
Цитата(Guest45 @  18.6.2015,  19:26 Найти цитируемый пост)
я не знал, где посмотреть

Для скалярных переменных и скалярных свойств - достаточно навести курсор мыша на переменную и секунду подождать.
В редакторе VBA в меню View есть Locals Window. Там ты можешь смотреть содержимое любых видимых в текущем контексте переменных. Удобно для объектных - можно просмотреть любые свойства (вернее, их значения) объекта.
А ещё там есть Watch Window. Там можно смотреть значения не только для переменных и свойств, но и для любых выражений.
НУ и тупой вывод значений (а также выполнение любых однострочных выражений - в т.ч. и для изменения значений) в Immediate Window тоже никто не отменяет. 

Автор: Guest45 19.6.2015, 09:11
Первые впечатления.

У меня проверка орфографии не знает букву "ё". Так что перед проверкой в переменной надо бы их заменить на "е", но это сравнительно редкий случай, и в более новых Офисах наверное этой проблемы нет.

Кажется, что "итератор" после каждой правки восстанавливает свою позицию, заново отсчитывая от самого начала текста.
Так что, чем дальше в лес тем толще партизаны, тем больше замедляется работа.
Поэтому большие тексты лучше обрабатывать, разделив их на фрагменты.
Зависит конечно от компьютера; у меня разумный максимум составил приблизительно 50 вордовых страниц.

Свой проблемный файл обработал. Некоторые огрехи остались, когда перенос попадал например в имена собственные и тогда не был удален, или слово уже содержало грамматическую ошибку.
Но эти единичные случаи вполне поправимы уже в ручную.

На этом тему считаю исчерпанной, всем спасибо!

Автор: Akina 19.6.2015, 11:15
Цитата(Guest45 @  19.6.2015,  10:11 Найти цитируемый пост)
Кажется, что "итератор" после каждой правки восстанавливает свою позицию, заново отсчитывая от самого начала текста.

Ну вообще по уму надо делать итерацию по словам не как по коллекции (при этом действительно возникают определённые побочные эффекты), а как по массиву. Не вижу особой сложности в переделке кода. Только не делай его циклом FOR - попадёшь на выход за пределы массива, организуй его как DO - LOOP или как WHILE - WEND с проверкой на достижение ТЕКУЩЕГО конца массива.
Цитата(Guest45 @  19.6.2015,  10:11 Найти цитируемый пост)
чем дальше в лес, тем больше замедляется работа.
Это на самом деле работа UNDO-буфера.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)