sergvg
Интересующийся
Offline
|
|
« : 12-05-2010 10:54 » |
|
Здравствуйте, уважаемые коллеги! Помогите, пожалуйста! подскажите, каким образом можно найти в документе Word все слова, перед которыми стоит специальный знак (например, '*') и записать их в массив, затем все полученные слова (вместе с предшествующим знаком) заменить на другой текст? пока пришло такое решение (поиск меток): $WordsCount = $File->Words->{Count}; my $pword; for $i (1..$WordsCount){ $word = $File->Words($i)->{Text}; if ($pword eq '*' ) { push @$words ,$word; } $pword = $word; }
и затем произвести замену с помощью этого my $search = $doc-> Content->Find; my $replace = $search-> Replacement;
$search-> {Text} = $oldtext; $replace-> {Text} = $newtext; $search-> Execute({Replace => wdReplaceAll});
Но я думаю, что есть более эффективный метод. Метод с закладками (bookmarks) мне не нравится, потому что неудобно клепать шаблоны. Намного нагляднее в тексте шаблона видеть метки, поэтому этот метод предлагать не нужно (уже есть у меня готовое решение с использованием закладок). Добавлено через 1 час, 45 минут и 39 секунд:В общем, у меня получился такой код для поиска и замены меток вида *Name my $Word = CreateObject Win32::OLE 'Word.Application' or die $!; $Word->{'Visible'} = 1;
my $File = $Word->Documents->Open(abs_path($ARGV[0]));
#$ActiveDoc = $Word->ActiveDocument;
my $replaces={'PrikazNum'=>'Номер приказа 222', 'Date'=>'Дата: 2010-01-02', 'sign'=>'Подпись: 2222'};
my $myRange = $File->Content; while ($myRange->{Find}->Execute ({FindText=>'*', Forward=>1}) ){ $foundrange=$myRange->Next({Unit=>wdWord, Count=>1}); $repltext = $replaces->{$foundrange->{Text}}; $foundrange->MoveStart({Unit=>wdCharacter, Count=>-1}); print "'$foundrange->{Text}' заменяем на '$repltext'\n"; $foundrange->{Text} = $repltext; }
Вопрос остался такой: как избежать появления пробелов в $foundrange->{Text} ? Сюда пробел попадает, другие символы нет (если в документе встречаются).
|
|
« Последнее редактирование: 12-05-2010 12:40 от sergvg »
|
Записан
|
|
|
|
baldr
|
|
« Ответ #1 : 13-05-2010 05:52 » |
|
sergvg, а регулярные выражения ты не пробовал? Судя по условию задачи - это самый подходящий вариант для тебя
|
|
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
RXL
|
|
« Ответ #2 : 13-05-2010 06:10 » |
|
Чего-то я не пойму: листинги на Perl, а раздел - VBA. Замеченные недостатки - нет проверки на наличие ключа: $repltext = $replaces->{$foundrange->{Text}}; Наверно стоит так: $foundrange->{'Text'} ~= m/^(\s*)(.*?)(\s*)$/;
if (exists($replaces->{$2}) { $foundrange->{'Text'} = $1 . $replaces->{$2} . $3; }
|
|
« Последнее редактирование: 13-05-2010 06:34 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
sergvg
Интересующийся
Offline
|
|
« Ответ #3 : 13-05-2010 07:08 » |
|
У меня вопросы не по Perl, а по VBA (перл я знаю отлично, а вот с VBA не работал совсем)!
Какие объекты использовать, и какие методы вызывать!
И в моём случае, проверку на наличие ключей хеша можно не делать, потому что документ (шаблон) сначала загружается на сервер, скриптом получается список меток. А затем, другим скриптом эти метки заполняются, где формируется хеш по списку параметров.
Прошу перенести тему обратно в VBA.
PS: о каких регулярных выражениях шла речь ? в VBA есть регеспы ?
со стороны Perl эти пробелы в конце, разумеется, я поубирал.
|
|
« Последнее редактирование: 13-05-2010 07:27 от RXL »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #4 : 13-05-2010 07:34 » |
|
Понятие "знаю отлично" у каждого свое. На мой взгляд для этого не хватает, для начала, use strict и вытекающих из этого ограничений на необъявленные переменные и голые слова, а также проверок, т.к. со strict все огрехи по вылезают как ошибки, причем, ошибка с отсутствующим ключем может вылезти уже в процессе эксплуатации. Т.ч. посторожнее с утверждениями...
К VBA вопрос отношения не имеет. Это работа с COM-объектами. То, что в VB и VBA все объекты являются COM-объектами, еще не ставит между ними знака равенства. Точно также можно работать с Вордом на любом другом языке. Я, к примеру, использую экспорт в Excel из Borland C++ Builder. Значит темы BCB тоже в VBA переносить?
Что и как у тебя формируется — мы не видим и, соответственно, знать не можем. Судим по приведенному коду и заданным вопросам.
|
|
« Последнее редактирование: 13-05-2010 07:36 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
sergvg
Интересующийся
Offline
|
|
« Ответ #5 : 13-05-2010 09:21 » |
|
Если мне нужно уточнить, узнать какие объекты, их свойства и методы использовать для того, чтобы поуправлять MS Word'ом, то причём тут Perl ?
а куски кода на Perl, потому что я пишу на Perl, и слабо знаю синтаксис VBA, чтобы привести к нему.
|
|
|
Записан
|
|
|
|
baldr
|
|
« Ответ #6 : 13-05-2010 10:58 » |
|
sergvg, если ты спрашиваешь про объектную модель Word, то так и говори. Мы видим конкретный вопрос: Вопрос остался такой: как избежать появления пробелов в $foundrange->{Text} ? Сюда пробел попадает, другие символы нет (если в документе встречаются). И отвечаем, что лучше уж использовать регулярные выражения, и RXL даже пример привел. Никто не говорил ни слова про VBA. Поскольку пример на Perl, то и очевидно что ожидается решение на Perl.
|
|
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
RXL
|
|
« Ответ #7 : 13-05-2010 12:57 » |
|
sergvg, если не знаешь, как-то делай просто: открывай документ, запускай запись макроса и выполняй действия руками (старайся делать минимум действий - только нужные), после чего в макросе видим последовательность действий с объектами. Код там не сложный - на Perl портируется чуть ли не один в один. Собственно говоря, у тебя похоже так и сделано. У меня получилось немного иначе: Selection.Find.Execute Selection.MoveRight Unit:=wdWord, Count:=1, Extend:=wdExtend
Но суть та же: если после "*слово" есть пробел, то он тоже выделяется. Думаю, что не надо ничего делать - бери, что дают, реж регулярными выражениями (в Перле!) и делай с ним что надо.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Sla
|
|
« Ответ #8 : 13-05-2010 13:29 » |
|
не знаю, есть ли регулярки в VBA, но в VB есть объект RegExp
Dim myRegExp As New RegExp
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
RXL
|
|
« Ответ #9 : 13-05-2010 13:43 » |
|
Слав, VBA тут не при чем - нету его. Есть Perl и COM-объект Word.Application.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
sergvg
Интересующийся
Offline
|
|
« Ответ #10 : 13-05-2010 17:33 » |
|
sergvg, если не знаешь, как-то делай просто: открывай документ, запускай запись макроса и выполняй действия руками (старайся делать минимум действий - только нужные), после чего в макросе видим последовательность действий с объектами. Код там не сложный - на Perl портируется чуть ли не один в один. Собственно говоря, у тебя похоже так и сделано. У меня получилось немного иначе: Selection.Find.Execute Selection.MoveRight Unit:=wdWord, Count:=1, Extend:=wdExtend
Но суть та же: если после "*слово" есть пробел, то он тоже выделяется. Думаю, что не надо ничего делать - бери, что дают, реж регулярными выражениями (в Перле!) и делай с ним что надо. так-то понятно, но я долго искал в хелпе, как получить в перле уже список отмеченных слов, ещё неясно было, как продолжить поиск (после изменения Range поиск зацикливался, начинаясь наверно или сначала, или поиск производился в измененном Range) Ну а то, что пробелы перлом на раз выкусываются - это элементарно. Думал, может есть какая-то опция, чтобы эти пробелы просто не попадали в результат. Было бы удобнее, если бы был поиск с регеспами, искал бы по /\*.(\w+)/. Или может есть, а я не знаю?
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #11 : 13-05-2010 19:49 » |
|
Полноценных регулярных выражений в Ворде нет, но можно делать примитивные шаблоны типа как в оболочке с именами файлов. Собственно, это описано в MSDN и даже в самом Ворде, когда открываешь поиск и делаешь его расширенным (и включи галку "Подстановочные знаки", а символы можно выбрать из выпадающего списка). Find object members: http://msdn.microsoft.com/en-us/library/bb257583.aspxПосмотри свойства: IgnoreSpace, MatchWildcards. Простые эксперименты руками в Ворде дали такой шаблон: \*<*> Это выбирает звездочку и слово за ним. Объекты Ворда: http://msdn.microsoft.com/en-us/library/bb225019.aspxДобавлено через 29 минут и 15 секунд:Вот макрос Ворда. Selection.Find.ClearFormatting Selection.Find.Replacement.ClearFormatting With Selection.Find .Text = "\*<*>" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = True End With Selection.Find.Execute With Selection.Find .Text = "\*<*>" .Replacement.Text = "1111" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = True End With With Selection If .Find.Forward = True Then .Collapse Direction:=wdCollapseStart Else .Collapse Direction:=wdCollapseEnd End If .Find.Execute Replace:=wdReplaceOne If .Find.Forward = True Then .Collapse Direction:=wdCollapseEnd Else .Collapse Direction:=wdCollapseStart End If .Find.Execute End With With Selection.Find .Text = "\*<*>" .Replacement.Text = "2222" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = True End With With Selection If .Find.Forward = True Then .Collapse Direction:=wdCollapseStart Else .Collapse Direction:=wdCollapseEnd End If .Find.Execute Replace:=wdReplaceOne If .Find.Forward = True Then .Collapse Direction:=wdCollapseEnd Else .Collapse Direction:=wdCollapseStart End If .Find.Execute End With With Selection.Find .Text = "\*<*>" .Replacement.Text = "3333" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = True End With With Selection If .Find.Forward = True Then .Collapse Direction:=wdCollapseStart Else .Collapse Direction:=wdCollapseEnd End If .Find.Execute Replace:=wdReplaceOne If .Find.Forward = True Then .Collapse Direction:=wdCollapseEnd Else .Collapse Direction:=wdCollapseStart End If .Find.Execute End With
Если его подчистить, то получится примерно следующее: Инициализация Selection.Find.ClearFormatting Selection.Find.Replacement.ClearFormatting
With Selection.Find .Text = "\*<*>" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchAllWordForms = False .MatchSoundsLike = False .MatchWildcards = True End With
Поиск Замена Selection.Find.Replacement.Text = "1111"
With Selection If .Find.Forward = True Then .Collapse Direction:=wdCollapseStart Else .Collapse Direction:=wdCollapseEnd End If
.Find.Execute Replace:=wdReplaceOne
If .Find.Forward = True Then .Collapse Direction:=wdCollapseEnd Else .Collapse Direction:=wdCollapseStart End If End With
|
|
« Последнее редактирование: 13-05-2010 20:23 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
sergvg
Интересующийся
Offline
|
|
« Ответ #12 : 14-05-2010 03:17 » |
|
спасибо, на досуге опробую.
|
|
|
Записан
|
|
|
|
|