Консультация № 177488
27.03.2010, 16:14
35.77 руб.
0 30 1
Уважаемые эксперты подскажите код как при помощи ВБА удалить в документе все «пустые» ссылки, перед удалением их выделять не нужно. «Пустые» ссылки это те, которые ссылаются на не существующие в документе закладки и на не существующие папки и документы, ссылки на адреса электронной почты и на адреса сайтов удалять не нужно. Удалять нужно только ссылку текст, который отображён на экране удалять не нужно. Спасибо Эндрю

Обсуждение

Неизвестный
31.03.2010, 17:22
общий
это ответ
Здравствуйте, Ципихович Эндрю.
Возможный вариант решения представлен в приложении.

Приложение:
Sub q177488()
Dim dest As String
Dim re As Object
Dim x As String

Set re = CreateObject("VBScript.RegExp")
With re
.Global = True
.Pattern = "(\s+\\(([lmnot])|(\*\s*(\w)+)))|(\s?HYPERLINK)|(\s?\x22)|(\x22\s?)"
End With

LinksCount = ActiveDocument.Fields.Count
For i = LinksCount To 1 Step -1
If (ActiveDocument.Fields(i).Type = wdFieldHyperlink) Then
' Закладка на URI или создание электронного письма
If (InStr(ActiveDocument.Fields(i).Code.Text, "mailto:") > 0) Or _
(InStr(ActiveDocument.Fields(i).Code.Text, "http://") > 0) Then
GoTo Skip
End If
dest = Trim$(re.Replace(ActiveDocument.Fields(i).Code.Text, ""))
' Ссылка на закладку в текущем документе
If (InStr(ActiveDocument.Fields(i).Code.Text, "\l") > 0) Then
If Not (Bookmarks.Exists(dest)) Then
ActiveDocument.Fields(i).Unlink
End If
GoTo Skip
End If
' Ссылка на папку или файл
On Error Resume Next
x = GetAttr(dest)
If err.Number <> 0 Then
ActiveDocument.Fields(i).Unlink
End If
On Error GoTo 0
End If
Skip:
Next
End Sub
5
Неизвестный
31.03.2010, 19:49
общий
Andrew Kovalchuk:
Спасибо за ответ, прокоментируйте пожалуйста строку

On Error GoTo 0
Я так понимаю в случае возникновения ошибки перейти к метке 0, а где эта метка, если предположить что в начало процедуры
тогда вопрос зачем туда, по второму кругу?? имеются ли ещё такие специальные метки например в конец цикла
Неизвестный
31.03.2010, 19:58
общий
Ципихович Эндрю:
Цитата: 238244
On Error GoTo 0
Я так понимаю в случае возникновения ошибки перейти к метке 0, а где эта метка, если предположить что в начало процедуры
тогда вопрос зачем туда, по второму кругу?? имеются ли ещё такие специальные метки например в конец цикла
Это включение стандартного способа обработки ошибок. Несколькими строками выше можно видеть как включается режим игнорирования ошибок - On Error Resume Next - и производится анализ возникающей ошибки - If err.Number <> 0 Then. Метка Skip в цикле For используется для перехода к следующей итерации цикла.
Неизвестный
01.04.2010, 05:15
общий
Andrew Kovalchuk:
Вы говорите
используется для перехода к следующей итерации цикла
я бы сказал по русски переход к концу цикла, то есть начало нового цикла

Для чего нужно On Error GoTo 0, куда переходит кокретно я так и не понял??????????

Так как Нот у меня не воспринимает, немножко изменил

Dim dest As String
Dim re As Object
Dim x As String

Удалено_ссылок = 0
Количество_ссылок = 0
Set re = CreateObject("VBScript.RegExp")
With re
.Global = True
.Pattern = "(\s+\\(([lmnot])|(\*\s*(\w)+)))|(\s?HYPERLINK)|(\s?\x22)|(\x22\s?)"
End With

LinksCount = ActiveDocument.Fields.Count
For i = LinksCount To 1 Step -1
If (ActiveDocument.Fields(i).Type = wdFieldHyperlink) Then
Количество_ссылок = Количество_ссылок + 1
'закладка на URL или создание электронного письма
If (InStr(ActiveDocument.Fields(i).Code.Text, "mailto:") > 0) Or _
(InStr(ActiveDocument.Fields(i).Code.Text, "http://") > 0) Then
GoTo Skip
End If

dest = Trim$(re.Replace(ActiveDocument.Fields(i).Code.Text, ""))
'ссылка на закладку в текущем документе

If (InStr(ActiveDocument.Fields(i).Code.Text, "\l") > 0) Then

If ActiveDocument.Bookmarks.Exists(dest) = False Then
ActiveDocument.Fields(i).Unlink: Удалено_ссылок = Удалено_ссылок + 1
End If
GoTo Skip
End If

'ссылка на папку или файл
On Error Resume Next
x = GetAttr(dest)
If Err.Number <> 0 Then
ActiveDocument.Fields(i).Unlink: Удалено_ссылок = Удалено_ссылок + 1
End If
On Error GoTo 0
End If
Skip:
Next

If Удалено_ссылок <> 0 Then MsgBox$ "В документе " & Количество_ссылок & " ссылок, удалено " & Удалено_ссылок & " пустых ссылок", vbOKOnly, "ВНИМАНИЕ"

Открыл чистый лист набрал слово поставил на него ссылку на существующую папку взяло её удалило, почему?????????

Неизвестный
01.04.2010, 14:19
общий
Ципихович Эндрю:
Цитата: 238244
Для чего нужно On Error GoTo 0, куда переходит кокретно я так и не понял??????????
Уже никто никуда не идет . Эта конструкция является командой интерпретатору обрабатывать ошибки в стандартном режиме, то есть при возникновении ошибки приостанавливать выполнение и выводить сообщение об ошибке. Как я уже отмечал, несколькими строками ранее командой
Цитата: 238244
On Error Resume Next
устанавливался иной способ обработки ошибок - при возникновении ошибки происходит ее игнорирование и переход к следующей строке кода.
Цитата: 238244
Открыл чистый лист набрал слово поставил на него ссылку на существующую папку взяло её удалило, почему?????????
Для обработки относительных путей следует заменить существующий блок обработки ссылок на файлы и папки на нижеприведенный
Код:
'ссылка на папку или файл
On Error Resume Next
If (InStr(dest, "../") = 1) Or (InStr(dest, "./") = 1) Then
dest = ActiveDocument.Path & "" & dest
End If
x = GetAttr(dest)
If err.Number <> 0 Then
ActiveDocument.Fields(i).Unlink: Удалено_ссылок = Удалено_ссылок + 1
End If
On Error GoTo 0
Неизвестный
01.04.2010, 20:02
общий
Andrew Kovalchuk:
Вы говорите:
то есть при возникновении ошибки приостанавливать выполнение и выводить сообщение об ошибке
Приведите пожалуйста пример как мне надо поставить ссылку специально чтобы наткнуться на это сообщение об ошибке
Спасибо Эндрю
Неизвестный
02.04.2010, 01:04
общий
Ципихович Эндрю:
Цитата: 238244
Приведите пожалуйста пример как мне надо поставить ссылку специально чтобы наткнуться на это сообщение об ошибке
Закомментируйте строку On Error Resume Next и создайте ссылку на несуществующий файл или папку. Во время выполнения вы получите ошибку 53 Файл не найден.
Неизвестный
02.04.2010, 18:36
общий
Andrew Kovalchuk:
Сейчас Вин рара нет под рукой не знаю как загрузился файл
тем не менее есть файл https://rfpro.ru/upload/2026
в нём есть ссылка на существующий файл, её удаляет почему??????????
Неизвестный
02.04.2010, 21:28
общий
Ципихович Эндрю:
Куда ссылается эта ссылка - {HYPERLINK "file:///L:\\Вещий%20Олег.doc" \l "q#q"}? Варианты ответа: 1. На файл Вещий Олег.doc 2. На место в документе q#q 3. На нечто с именем Вещий Олег.docq#q
Расскажите как вам удалось поставить такую ссылку? Вариант "правка руками" не предлагать.
Неизвестный
03.04.2010, 08:17
общий
Andrew Kovalchuk:
В вопросе было сказано: как при помощи ВБА удалить в документе все «пустые» ссылки
Эта ссылка не пустая, а её удаляет, значит Ваше решение ещё надо усовершенствовать
Ссылается на закладку q в файле Вещий Олег.doc, по адресу ......
Как я поставил ссылку
в файле выделил часть текста нажал Вставить гиперссылку нажал в левом верхнем углу Файлом, вэб страницей, выбрал файл
потом нажал в правом верхнем углу закладка и выбрал её
Почему Вы говорите "правка руками" не предлагать, в вопросе по этому ничего не сказано, код должен справиться с любыми вариантами
ЭТА ССЫЛКА НЕ ПУСТАЯ!!!!!, А ЕЁ УДАЛИЛ ВБА, ПО ВАШЕЙ УКАЗКЕ, ИСПРАВЬТЕ ПОЖАЛУЙСТА
Неизвестный
03.04.2010, 17:27
общий
Ципихович Эндрю:
Цитата: 238244
Как я поставил ссылку
в файле выделил часть текста нажал Вставить гиперссылку нажал в левом верхнем углу Файлом, вэб страницей, выбрал файл
потом нажал в правом верхнем углу закладка и выбрал её
Я проделал действия соответственно с указанной последовательностью и получил ссылку вида
{HYPERLINK "file:///D:\\MyDoc\\RfPro\\Вещий%20Олег.doc" \l "q"},
ваша ссылка имеет вид
{HYPERLINK "file:///D:\\MyDoc\\RfPro\\Вещий%20Олег.doc" \l "q#q"}
- разница выделена цветом. Что в данном случае обозначает символ #?
Что делать со ссылкой, которая ссылается на несуществующую закладку в существующем документе? Удалять?
Неизвестный
03.04.2010, 18:04
общий
Andrew Kovalchuk:
Что делать со ссылкой, которая ссылается на несуществующую закладку в существующем документе? Удалять?
Да потому, что я её считаю пустой

Неизвестный
03.04.2010, 21:16
общий
Ципихович Эндрю:
Цитата: 238244
Почему Вы говорите "правка руками" не предлагать, в вопросе по этому ничего не сказано, код должен справиться с любыми вариантами
ЭТА ССЫЛКА НЕ ПУСТАЯ!!!!!, А ЕЁ УДАЛИЛ ВБА, ПО ВАШЕЙ УКАЗКЕ, ИСПРАВЬТЕ ПОЖАЛУЙСТА
Код может обработать некоторое конечное множество разумных значений. Ниже прилагается вариант, умеющий проверять ссылки на закладки в существующих документах.
Код:
Dim bm As String
Dim src As String
Dim re_bm, ms, d, adn, cdn

Function isPathOfFileName(ByVal st As String) As Boolean
isPathOfFileName = ((InStr(st, ".") > 0) Or (InStr(st, "..") > 0) Or (InStr(st, "\") > 0) Or (InStr(st, "/") > 0))
End Function

Sub getTargets(st As String)
Set ms = re_bm.Execute(st)

bm = ""
src = ""

If (ms.Count = 1) Then
If (isPathOfFileName(ms(0))) Then
src = ms(0)
Else
bm = ms(0)
End If
End If

If (ms.Count = 2) Then
If (isPathOfFileName(ms(0))) Then
src = ms(0)
bm = ms(1)
Else
src = ms(1)
bm = ms(0)
End If
End If

If (src <> "") Then
src = Replace(src, """", "")
src = Replace(src, "file:///", "")
src = Replace(src, "%20", " ")
End If
If (bm <> "") Then
bm = Replace(bm, """", "")
End If
End Sub

Sub q177488()
Dim x As Integer
Dim fcount As Integer
Dim hl As String

Set re_bm = CreateObject("VBScript.RegExp")
With re_bm
.Global = True
.Pattern = "\x22.+?\x22"
End With

fcount = ActiveDocument.Fields.Count
For i = fcount To 1 Step -1
If (ActiveDocument.Fields(i).Type <> wdFieldHyperlink) Then
GoTo Skip
End If

hl = ActiveDocument.Fields(i).Code.Text

' ссылки на страницы в интернете и электронные письма не обрабатывать
If (InStr(hl, "mailto:") > 0) Or _
(InStr(hl, "http://") > 0) Then
GoTo Skip
End If

Call getTargets(hl)
' получение значений полей ссылок

' Ссылка на папку или файл
If (src <> "") Then
On Error Resume Next
If (InStr(src, "./") = 1) Or (InStr(src, "../") = 1) Then
' относительные пути -> в абсолютные
src = ActiveDocument.Path & "" & src
End If
x = GetAttr(src)
If err.Number <> 0 Then ' если ссылка в несуществующем направлении
Beep
ActiveDocument.Fields(i).Unlink ' преобразовать в текст
Else
If (x <> 16) Then ' если ссылка на файл
If (bm <> "") Then ' и есть ссылка на закладку в нем
adn = ActiveDocument.Name
Documents.Open src, ReadOnly = True
cdn = ActiveDocument.Name
flag = (ActiveDocument.Bookmarks.Exists(bm) = False)
Documents(cdn).Close
Documents(adn).Activate
If flag Then ' и она не найдена
Beep
ActiveDocument.Fields(i).Unlink ' преобразовать в текст
End If
End If
End If
End If
On Error GoTo 0
GoTo Skip
End If

If (bm <> "") Then ' если ссылка на закладку в текущем документе
If (ActiveDocument.Bookmarks.Exists(bm) = False) Then ' но она не найдена
Beep
ActiveDocument.Fields(i).Unlink ' преобразовать в текст
End If
GoTo Skip
End If
Skip:
Next i
End Sub
Остался без ответа вопрос
Цитата: 299564
{HYPERLINK "file:///D:\\MyDoc\\RfPro\\Вещий%20Олег.doc" \l "q#q"}
Что в данном случае обозначает символ #?
Как понимать такую ссылку? Символ # не является допустимым знаком в имени закладки.
Неизвестный
04.04.2010, 06:48
общий
Andrew Kovalchuk:
Согласно теориии я не знаю откуда появляются эти значения q#q
Но думаю что это типа повторение мать учения q q или что то вроде Баден баден, одним словом надо теорию знать, и всё станет ясно, где посмотреть я не знаю
Но Вы же прекрасно понимаете, что знак # надо удалять, а справа и слева от него будут одни и те же символы, в данном случае q и q
В то же время я попробовал поставить ссылку на длинную закладку типа рпрпрпрпрпрпрпрпрппрпрп, повторения не получил, отчего это зависит осталось только гадать
Неизвестный
05.04.2010, 19:33
общий
Andrew Kovalchuk:
Который Остался без ответа вопрос
будет иметь решение???????77
Неизвестный
05.04.2010, 20:18
общий
Ципихович Эндрю:
Этот вопрос остался без ответа?
Цитата: 238244
Согласно теориии я не знаю откуда появляются эти значения q#q
Но думаю что это типа повторение мать учения q q или что то вроде Баден баден, одним словом надо теорию знать, и всё станет ясно, где посмотреть я не знаю
Но Вы же прекрасно понимаете, что знак # надо удалять, а справа и слева от него будут одни и те же символы, в данном случае q и q
А если символы будут разные? Тогда это уже не "повторение мать учения", а понимай как хочешь? По документации после ключа \l должно стоять валидное наименование места для перехода. Мне не удалось найти информацию о назначении символа # в такой конструкции и описания того, что представляют из себя значения слева и справа от него. Посему считаю нужным определиться (или договориться), что считать корректной ссылкой в случае наличия "злополучного" символа.
Неизвестный
05.04.2010, 21:33
общий
Andrew Kovalchuk:
Я вот пошёл у Вас на поводу имею в виду со ссылкой типа РЭФ, не знаю, кто ими пользуется? Будем договариваться: ссылками считать то что, ставиться обычным способом через вставить гиперссылку, и после того как поставил пользователь она выделяется синим цветом и подчёркиванием, а после её просмотра меняет цвет и нажав на её выделяется объект будь то закладка, папка, файл.
То есть будем пользоваться следующими строками:
Цикл = ActiveDocument.Hyperlinks.Count
Имя = ActiveDocument.Hyperlinks(i).Name
ActiveDocument.Hyperlinks(i).Delete и удалится не выделяясь
и в переменную Имя насколько я понял попадёт всё то что нужно в том числе без злополучного знака #
И всё также будем считать пустой ссылкой ссылку даже на существующий файл но если в нём отсутсвует нужная для ссылки закладка
Неизвестный
05.04.2010, 23:05
общий
Ципихович Эндрю:
Цитата: 238244
Я вот пошёл у Вас на поводу имею в виду со ссылкой типа РЭФ, не знаю, кто ими пользуется?
К чему здесь этот выпад? В данном вопросе, до вашего упоминания, не было ни слова о ссылках типа REF.
Цитата: 238244
Будем договариваться: ссылками считать то что, ставиться обычным способом через вставить гиперссылку, и после того как поставил пользователь она выделяется синим цветом и подчёркиванием, а после её просмотра меняет цвет и нажав на её выделяется объект будь то закладка, папка, файл.
В этом вопросе только гиперссылки и были героями обсуждения.
Цитата: 238244
То есть будем пользоваться следующими строками:
Цикл = ActiveDocument.Hyperlinks.Count
Имя = ActiveDocument.Hyperlinks(i).Name
ActiveDocument.Hyperlinks(i).Delete и удалится не выделяясь
и в переменную Имя насколько я понял попадёт всё то что нужно в том числе без злополучного знака #
Если бы все было так как вы описали, то я бы не парился с ненужными вопросами и не отнимал ваше время. Свойство Name не является подходящим для получения нужной информации (посмотрите, например, какое значение у этого свойства когда ссылка указывает на существующий файл).
Неизвестный
06.04.2010, 05:41
общий
Andrew Kovalchuk:
За моё время не беспокойтесь
Вы говорите Свойство Name не является подходящим для получения нужной информации
Сделайте как считаете нужным
Неизвестный
06.04.2010, 15:09
общий
Ципихович Эндрю:
Цитата: 238244
За моё время не беспокойтесь
Вы говорите Свойство Name не является подходящим для получения нужной информации
Сделайте как считаете нужным
Да я как бы и за свое тоже . Как я считал возможным сделать - вы можете наблюдать в моих постах с кодом. Для корректных закладок последний вариант кода совершенно работоспособен. До прояснения ситуации с символом # в имени закладки других вариантов у меня не будет. В настоящее время могу лишь предложить разделить строку с символом # и взять только левую его часть [i]или[/i] только правую в качестве имени закладки.
Неизвестный
06.04.2010, 16:56
общий
Andrew Kovalchuk:
Честно говоря я не понял, когда например ссылка на папку, код поля="папка1" как Вы извлекаете всё недостающее, что в начале то есть например D:\\MyDoc\\RfPro
и как Вы отличаете ссылается на папку или файл или на закладку, закладку в этом документе или в другом?????7
Неизвестный
06.04.2010, 17:06
общий
Andrew Kovalchuk:
То есть от чего зависит что иногда, например
Trim(ActiveDocument.Fields(i).Code.Text)="папка1"
иногда=HYPERLINK "file:///D:\\MyDoc\\RfPro\\Вещий%20Олег.doc" \l "q#q"


В ЭТОМ СЛУЧАЕ Trim(ActiveDocument.Fields(i).Code.Text)="папка1"
КУДА ДЕЛОСЬ НАЧАЛО, НАПРИМЕР D:\\MyDoc\\RfPro\\
Неизвестный
10.04.2010, 14:29
общий
Andrew Kovalchuk:

Я правильно понял, что в представленном Вами коде от 03.04.2010, 21:16 вставив его, появится две разделяющие полосы
то есть разделит эту часть

Dim bm As String
Dim src As String
Dim re_bm, ms, d, adn, cdn
'
'
здесь я специально вставил две ремарки, чтобы было видно, что там re_bm, а не re bm
__________________________________

от этой части

Function isPathOfFileName(ByVal st As String) As Boolean
isPathOfFileName = ((InStr(st, ".") > 0) Or (InStr(st, "..") > 0) Or (InStr(st, "\") > 0) Or (InStr(st, "/") > 0))
End Function
___________________
а затем от этой части

Sub getTargets(st As String)
Set ms = re_bm.Execute(st) - так вот здесь ошибка № 424??????? почему????????

Что прямо такой уж великий код без функций и Call не обойтись????????????? Вы никогда не получали Ту ларге????, я получал до этого Вам далеко!!!!!!!!!!!!



Неизвестный
10.04.2010, 18:12
общий
Ципихович Эндрю:
Цитата: 238244
Я правильно понял, что в представленном Вами коде от 03.04.2010, 21:16 вставив его, появится две разделяющие полосы
Таки да.
Цитата: 238244
Что прямо такой уж великий код без функций и Call не обойтись????????????? Вы никогда не получали Ту ларге????, я получал до этого Вам далеко!!!!!!!!!!!!
Привычка. Гораздо проще разбираться в структурированном коде (и функции из двух-десяти строк), чем искать нужное место в куче написанного левой ногой непонятно чего.
Неизвестный
10.04.2010, 19:26
общий
Andrew Kovalchuk:
В этой части Вы не ответили
Sub getTargets(st As String)
Set ms = re_bm.Execute(st) - так вот здесь ошибка № 424??????? почему????????
Неизвестный
10.04.2010, 23:35
общий
Ципихович Эндрю:
Цитата: 238244
В этой части Вы не ответили
Sub getTargets(st As String)
Set ms = re_bm.Execute(st) - так вот здесь ошибка № 424??????? почему????????
Это "Run Time Error '424': Object Required"?
В своем тестовом файле я ошибок не наблюдаю. Как мне ее воспроизвести?
Неизвестный
11.04.2010, 13:27
общий
Andrew Kovalchuk:
Да эта ошибка которую я называю № 424 и есть "Run Time Error '424': Object Required"
Пока сам не могу воизпроизвести эту ошибку как получится ещё раз запомню и напишу
Неизвестный
17.04.2010, 13:16
общий
Andrew Kovalchuk:
Опять проблема высылаю модуль
https://rfpro.ru/upload/2133
без пароля

и файл 001Kovalchuk.doc
https://rfpro.ru/upload/2134
без пароля
И вот там в файле лдну единственную ссылку удаляет, но она не пустая, почему????
Неизвестный
17.04.2010, 21:59
общий
Ципихович Эндрю:
Цитата: 238244
Опять проблема высылаю модуль ... И вот там в файле лдну единственную ссылку удаляет, но она не пустая, почему????
В приведенном примере макросом неправильно интерпретировались значения ключей. Пришлось изменить подход для обхода такой неприятности. Посмотрите текст измененного макроса. Я проверил на вашем файле и на своем тестовом примере - должно быть все корректно.
Неизвестный
18.04.2010, 05:23
общий
Andrew Kovalchuk:
Спасибо, будут проблемы напишу
Форма ответа