Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Word VBA Замена

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2

Открыть новую тему     Написать ответ в эту тему

Devust

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Добрый день!
 
Спасибо за помощь!
 
Да, программа работает медленно.  
Но, всё-таки, что-то не так.
 
Во-первых, как я вижу, текстовый файл, где указаны замены, должен быть строго форматирован, т.е. все элементы должны быть только через один пробел. Иначе получаются пустые элементы строкового списка (SPLIT), именно их я и убирал ранее.
Дело в том, что этот файл будут править пользователи и надеяться, что они будут строго соблюдать правило одного пробела, - вряд ли можно.
Далее, странно, но у меня Ваша программа вовсе не работает.
Я вижу, что она обрабатывает слово целиком - от пробела до пробела или запятой (точки). Но тогда у меня не заменяет НБС7 на НАС101. Просто БС7, да, меняет.
 
Да и на что тратится время тоже не понятно. А в отчёте 250 листов. ))
 

Всего записей: 18 | Зарегистр. 15-01-2013 | Отправлено: 07:25 24-02-2016 | Исправлено: Devust, 07:30 24-02-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Но тогда у меня не заменяет НБС7 на НАС101

Может быть, это потому, что в вашем исходном файле нет НБС7 ?
 
А вообще, символы, которые могут составлять слова - описаны в константе Alphabet.
Всё, чего там нет, считается разделителями между словами.
В моём варианте там не указана латиница. Если у вас она используется в поисковых строках, добавьте латиницу в Alphabet.

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 12:29 27-02-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
1. Split. Вы не первый, кто столкнулся с этой проблемой. Предлагаю взять сплит  отсюда.
 
Я так и сделал и у меня вызов стал таким:

Код:
Public Sub zamena_po_predl()
Dim S As String
Dim s_split() As String
  Open "e:\st.txt" For Input As #1
  While Not EOF(1)
    Input #1, S
    If S <> "" Then
      S = Trim(S):   s_split() = SplitEx(S, " ", , True)
      If UBound(s_split) = 2 Then
        ReDim Preserve s_split(3)
        s_split(3) = ""
      End If
      MyReplace s_split(0), s_split(1), s_split(2), s_split(3)
    End If
  Wend
  Close #1
End Sub

 
2. Тормоза. Похоже, весь пар уходит в обращения к ActiveDocument.Characters, так что предлагаю вернуться к извлечению предложениями.
 
Например, так:

Код:
Sub MyReplace(SearchS, ReplaсeS, DownS, UpS As String)
  Const Alphabet = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя-АБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ1234567890abcdefghijklmnopqarstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  Dim r As Range
   
  S = ""
  For j = 1 To ActiveDocument.Sentences.Count
    S = ActiveDocument.Sentences(j)
    Wrd = False
    Wrdb = 0
    WrdE = 0
    i = 1
    While i <= Len(S)
      If InStr(Alphabet, Mid(S, i, 1)) > 0 Then
        If Not Wrd Then
          Wrd = True
          Wrdb = i
        End If
      Else
        If Wrd Then
          WrdE = i - 1
          Set r = ActiveDocument.Sentences(j)
          r.SetRange Start:=r.Start + Wrdb - 1, End:=r.Start + WrdE
          If r.Text = SearchS Then
            S = Mid(S, 1, Wrdb - 1) & ReplaсeS & DownS & UpS & Mid(S, WrdE + 1, Len(S) - WrdE)
            r.Delete
            r.InsertAfter (ReplaсeS)
            i = Wrdb - 1 + Len(ReplaсeS)
            Set r = ActiveDocument.Sentences(j)
            r.SetRange Start:=r.Start + i, End:=r.Start + i
            r.InsertAfter (DownS)
            r.Font.Subscript = True
            i = i + Len(DownS)
            If UpS <> "" Then
              Set r = ActiveDocument.Sentences(j)
              r.SetRange Start:=r.Start + i, End:=r.Start + i
              r.InsertAfter (UpS)
              r.Font.Superscript = True
              i = i + Len(UpS)
            End If
          End If
          Wrd = False
        End If
      End If
      i = i + 1
    Wend
  Next j
End Sub

 
На вашем примере, вроде как, работает. Время работы стало приемлемым. Если нужно ещё ускорить, можно попробовать запихать всё сразу в S, но надо экспериментировать. Удаление середины из больших строк может съесть весь выигрыш от меньшего количества обращений к ActiveDocument

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 19:01 27-02-2016 | Исправлено: KDPoid, 19:02 27-02-2016
Devust

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Ой, спасибо большое.
 
Пример только мудрёный получился.
Со сплитом (SplitEx) - совсем муторно разбираться. Скопировал к себе, потом обязательно разберу, но для меня и мой простенький вариант подходит.
 
Но всё-же не пойму. Ваша программа работает со словом целиком - она же не заменяет
НБС7 на НАС101  (<что-то>БС7 на <то же что-то>АС101)
 
Но, определённо я нашёл в вашей программе, что искал:
Никак не мог понять как работает Range
 r.SetRange Start:=r.Start + i, End:=r.Start + i  
 r.InsertAfter (DownS)   и т.д.
 
В общем, я всё-таки, оставил свой вариант. Но ))
Теперь никак не могу понять одну фишку.
 
Public Sub zamena_po_predl()  
Const razd = "., "
 Dim s As String
 Dim i, j, l, k, cs, csi, ri As Integer
 Dim s_split() As String
 Dim s_split_all() As String
 Dim yes_instr, yes_zamena As Boolean
 Dim r As Range
 
   Open "d:\plast112test.txt" For Input As #1
          cs = -1
     While Not EOF(1)
       Input #1, s
       If s <> "" Then
          s = Trim(s):   s_split() = Split(s):   j = -1:  l = UBound(s_split): cs = cs + 1
            For i = 0 To l
              If s_split(i) <> "" Then
                 j = j + 1:   s_split(j) = s_split(i)
              End If
            Next i
            ReDim Preserve s_split(j)
          l = UBound(s_split)
 
            ReDim Preserve s_split_all(0 To 3, 0 To cs)
            For i = 0 To l
              s_split_all(i, cs) = s_split(i)
            Next i
 
       End If        
     Wend            
   Close #1
 
   For i = 1 To ActiveDocument.Sentences.Count
     For csi = 0 To cs
 
        yes_instr = True
       Do While yes_instr
            j = InStr(1, ActiveDocument.Sentences(i), s_split_all(0, csi))
         If j <> 0 Then
            yes_zamena = False
 
            If InStr(razd, ActiveDocument.Sentences(i).Characters(j + Len(s_split_all(0, csi)))) > 0 Then
               yes_zamena = True
            End If
 
            If yes_zamena Then
 
               Set r = ActiveDocument.Sentences(i)
                   r.SetRange Start:=j - 1, End:=j + Len(s_split_all(0, csi)) - 1
                   r.Delete
                   r.InsertAfter (s_split_all(1, csi))
                   j = j + Len(s_split_all(1, csi)) - 1
 
               If s_split_all(2, csi) <> "" Then
               Set r = ActiveDocument.Sentences(i)
                   r.SetRange Start:=j, End:=j
                   r.InsertAfter (s_split_all(2, csi))
                   r.Font.Subscript = True
                   j = j + Len(s_split_all(2, csi))
               End If
               If s_split_all(3, csi) <> "" Then
 
               Set r = ActiveDocument.Sentences(i)
                   r.SetRange Start:=j, End:=j
                   r.InsertAfter (s_split_all(3, csi))
                   r.Font.Superscript = True
                   j = j + Len(s_split_all(3, csi))
               End If
 
            End If      
          Else      
            yes_instr = False
         End If  
       Loop    
     Next csi
   Next i  
 
End Sub
 
Фишка в том, что в разных случаях удаляется разный диапазон.
Видимо именно в указании начала и конца диапазона, который следует удалить, я что-то делаю не правильно.
Не могу пока понять как правильно.  
откуда и как управляется у Вас r.Start
я у себя определяю однозначно, однако к чему-то есть ещё привязки. Расскажите, плиз, это очень полезная функция.
 
 
 
Добавлено:
Вот, например:
 
Сначала:  Слово НБС7 слово слово слово, БС7.
 
Стало:      Слово НАС101 слово слово слово,АС.101
 
Вообще катавасия какая-то.
Съелся пробел после запятой, а 10 и 1 вставились после точки.
 
Как я вижу, что после определения set range,  r.Start = 0
Почему тогда после второго нахождения БС7 диапазон начинает болтать в разные стороны?
Ведь перед каждой заменой стоит  
 
Set r = ActiveDocument.Sentences(i)  
 
 
 
Добавлено:
Ничего не понимаю.
Закрыл ворд, открыл - всё прошло нормально.
Начал в ворде испытывать разные варианты, запускаю (F8) программку, топою по строкам, и вижу, что снова пробелы съедаются. Где что какое эхо с прошлых выполнений остаётся?
 
Это как randomize в начале нужно ставить, чтоб случайные числа не повторялись.
Здесь что-ли также?

Всего записей: 18 | Зарегистр. 15-01-2013 | Отправлено: 12:59 01-03-2016 | Исправлено: Devust, 13:47 01-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Мне кажется, что координаты диапазона задаются от начала документа.
Set r = ActiveDocument.Sentences(i) ' r - диапазон i-го предложения.
При этом у него r.Start вовсе не ноль.
а дальше, чтобы установить диапазон на j-й символ внутри приложения, я к его началу прибавляю j
r.SetRange Start:=r.Start + j - 1, End:=r.Start + j + <нужная длина диапазона в символах>  

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 19:11 01-03-2016
Devust

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Ну да, так и есть.
При пошаговом выполнении после строчки  
Set r = ActiveDocument.Sentences(i)
в окне Immediate r.Start = 0
Да, отчёт идёт от начала предложения.
Но почему то старт-енд пляшут.
 
 
Ага! Вот интересный момент!
Есть разница, есть ли что-то слева или нет.
 
1 вариант:
Было:  Слово НБС7 слово слово слово, НБС7, слово слово НБС7.  
Стало: Слово НАС101 слово слово слово, НАС101, слово слово НАС101.  
 
2 вариант:
Было:   Слово БС7 слово слово слово, БС7, слово слово БС7.  
Стало:  Слово АС101слово слово слово, АС101, слово словоАС.101  
 
Первое БС7 - съелся пробел справа, второй БС7 нормально, последний вообще не о чём.
 
Добавлено:
Ещё вопрос.
 
Искомое БС7  (НБС7) есть в таблицах
 
В принципе слева может быть текст, но вот у меня как пример есть табличка, где строка этим НБС7 и заканчивается.
 
Как программно определить символ конца ячейки?
 
Ведь он же должен быть здесь, к примеру:
ActiveDocument.Sentences(i).Characters(j + 1)
 
Впрочем ругается, даже если я ищу символ перевода строки
Пробовал все варианты:
Chr(13), ChrW(13), ChrW$(13)  - Ругается: "Запрашиваемый номер семейства не существует"
 
а уж как будет символ конца ячейки...
там что-то типа Chr(13)+chr(10) или Chr(13)+chr(7)
Но как точно?

Всего записей: 18 | Зарегистр. 15-01-2013 | Отправлено: 06:36 02-03-2016
Открыть новую тему     Написать ответ в эту тему

Страницы: 1 2

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Word VBA Замена


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru