01 |
Все кто когда-либо сталкивался с подстановочными символами (Wildcards) знают, что это достаточно убогая попытка реализовать в VBA механизм подобный регулярным выражениям в других более развитых языках. Помимо более скудных возможностей (я уже не говорю о невозможности указания количества «ноль-или-один») данный механизм также ограничен и в сложности выстраиваемых выражений, и те кто пытался решить более-менее сложные задачи не раз сталкивался с ошибкой Поле "Найти" содержит слишком сложное выражение с использованием подстановочных символов. Отсюда и возникла необходимость воспользоваться более могущественным инструментом — регулярными выражениями. |
|
02 | VBA |
1 2 3 4 5 6 7 8 9 10 11 Dim objRegExp, matches, match
' В первую очередь получаем объект VBScript.RegExp
Set objRegExp = CreateObject("VBScript.RegExp")
' Далее задаем основные параметры
With objRegExp
.Global = True
.IgnoreCase = False
.pattern = "pattern"
End With |
|
03 |
Здесь, конечно, каждый кодер обрадуется — вызываем Replace и все ок! |
|
04 | VBA |
1 Set matches = objRegExp.Replace(ActiveDocument.Content, "replacementstring") |
|
05 |
Но при запуске, конечно же, будет выдана ошибка. Это связано с тем, что метод Replace объекта VBScript.RegExp принимает на вход первым параметром строковую переменную, а не объект (в нашем случае ActiveDocument.Content), и возвращает этот метод также измененную строку, а не вносит изменение во входящую, отсюда и танцы с бубнами: |
|
06 | VBA |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Set matches = objRegExp.Execute(ActiveDocument.Content)
' Придется обрабатывать каждое вхождение
For Each match In matches
Set matchRange = ActiveDocument.Content
With matchRange.Find
.Text = match.Value
.Replacement.Text = "replacementstring"
.MatchWholeWord = True
.MatchCase = True
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = False
.Execute Replace:=wdReplaceOne
End With
Next |
|
07 |
Ну хорошо, скажете вы, ну а если нам нужно переформатировать данные по аналогии с выражениями типа $1-$3-$2 (т. н. «обратные ссылки» в регулярных выражениях), т. е. как к примеру из 926-5562214 получить +7 (926) 556-22-14. Это тоже достаточно просто, здесь они тоже есть — единственное отличие — нумерация найденных групп начинается не с нуля, а единицы — $1. Давайте пока отвлечемся от нашего документа и посмотрим как это можно сделать с обычной строковой переменной: |
|
08 | VBA |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Dim objRegExp, matches, match
Set objRegExp = CreateObject("VBScript.RegExp")
Dim strSearch As String
Dim strResult As String
strSearch = "Пусть у нас есть несколько телефонов 8495-3584512, 8800-4852620 и, к примеру, 8950-5628585"
With objRegExp
.Global = True
.IgnoreCase = False
.pattern = "8(\d{3})-(\d{3})(\d{2})(\d{2})"
End With
strResult = objRegExp.Replace(strSearch, "+7 ($1) $2-$3-$4")
Debug.Print strResult
' Результат: ... |
|
09 | На заметку: |
12 строка выделена для того чтобы подчеркнуть каким образом было разделено указание на подгруппы ($2, $3 и $4), ведь выражение (\d{3})(\d{2})(\d{2}) эквивалентно (\d{7}). Но во втором случае, рекурсивный запрос содержал бы все 7 цифр.
|
Изучайте регулярные выражения!
|
10 |
Но поскольку, как уже говорилось выше, вместо входной строки у нас объект ActiveDocument.Content, такой метод не подойдет для работы. Придется пойти на хитрость — объединить два предыдущих кода: |
|
11 | VBA |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Set objRegExp = CreateObject("VBScript.RegExp")
With objRegExp
.Global = True
.IgnoreCase = False
.pattern = "8(\d{3})-(\d{3})(\d{2})(\d{2})"
End With
Set matches = objRegExp.Execute(ActiveDocument.Content)
Dim strReplacement As String
For Each match In matches
Set matchRange = ActiveDocument.Content
' Перед каждой заменой заранее формируем строку, которой нужно будет заменить вхождение
strReplacement = objRegExp.Replace(match.Value, "+7 ($1) $2-$3-$4")
With matchRange.Find
.Text = match.Value
.Replacement.Text = strReplacement
.MatchWholeWord = True
.MatchCase = True
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = False
.Execute Replace:=wdReplaceOne
End With
Next |
|
12 |
Оборачиваем в оболочку-функцию и, вуаля: |
|
13 | VBA |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 Sub ВыполнитьГруппуПреобразований_RegExp() ... Private Sub Выполнить_RegExp(pattern As String, patternExpr As String) ... |
|
14 |
Нельзя умолчать о существовании, к сожалению, некоторых ограничений в синтаксисе регулярных выражений при использовании объекта VBScript.RegExp в VBA. Эти ограничения провоцируют ошибку Run-time error '5017' Application-defined or object-defined error. Вот некоторые из них: |
|
15 |
|
|
17 |
Похожие запросы:
|
|