Я не эксперт по Regex, поэтому я использую тестовую систему, чтобы помочь мне в разработке паттернов.Я попытался сопоставить ваш шаблон и некоторые варианты с рядом строк, которые соответствуют вашим предметам.Раньше я не думал о синхронизации разных паттернов, но теперь добавил это в качестве опции к своему тестовому устройству.Приведенные ниже результаты оказались не такими, как я ожидал.
Pattern Text Duration
(Reg).*(Exp) xxxRegyyyExpzzz 0.00000216
(Reg).*(Exp) xxxxRegExpzzz 0.00000212
(Reg).*(Exp) xxxxxRegyEyyExpzzz 0.00000220
(Reg).*(Exp) xxxxxxRegyyExyExpzzz 0.00000220
Reg.*Exp xxxRegyyyExpzzz 0.00000199
Reg.*Exp xxxxRegExpzzz 0.00000198
Reg.*Exp xxxxxRegyEyyExpzzz 0.00000204
Reg.*Exp xxxxxxRegyyExyExpzzz 0.00000205
Reg.*?Exp xxxRegyyyExpzzz 0.00000205
Reg.*?Exp xxxxRegExpzzz 0.00000188
Reg.*?Exp xxxxxRegyEyyExpzzz 0.00000214
Reg.*?Exp xxxxxxRegyyExyExpzzz 0.00000220
Синхронизация подпрограмм VBA сложна, поскольку фоновый интерпретатор и подпрограммы ОС могут существенно влиять на время.Я должен увеличить количество повторений до 10 000 000, прежде чем общая продолжительность будет достаточной для того, чтобы я посчитал среднюю продолжительность надежной.
Как видите, удаление скобок захвата экономит немного времени, хотя вам понадобятся тысячи электронных писем.прежде чем вы заметите.Только количество символов между "Reg" и "Exp", кажется, имеет большое влияние.
Я не понимаю, почему первые два шаблона работают..*
считается жадным.Он должен соответствовать каждому символу до конца строки или до следующего перевода строки.Шаблон не должен найти «Exp», потому что они соответствуют .*
.Только ленивый .*?
должен был прекратить сопоставлять символы, когда он нашел «Exp».Либо я неправильно понял жадное сравнение, либо ленивое сопоставление, либо движок VBA Regex не рассматривает .*
как жадное.
Мой вывод состоит в том, что сопоставление регулярных выражений не является причиной медленной работы вашей программы.Я предлагаю вам попробовать предложение Тима.IAmANerd2000 добавил подпрограмму, демонстрирующую предложение Тима, но с тех пор он / она удалил его.(Я вижу удаленные ответы, потому что моя репутация превышает 10 тыс.). Возможно, Тим хотел бы добавить ответ, демонстрирующий его предложение.
Я включаю ниже свой тестовый жгут, если вы считаете его полезным.Его вывод для шаблона и текста:
===========================================
Pattern: "(Reg).*(Exp)"
Text: "xxxRegyyyExpzzz"
Av Durat'n: 0.00000216
-------------------------------------------
Match: 1
Value: "RegyyyExp"
Length: 9
FirstIndex: 3
SubMatch: 1 "Reg"
SubMatch: 2 "Exp"
===========================================
Option Explicit
Sub Test2()
Dim Patterns As Variant
Dim Texts As Variant
Texts = Array("xxxRegyyyExpzzz", _
"xxxxRegExpzzz", _
"xxxxxRegyEyyExpzzz", _
"xxxxxxRegyyExyExpzzz")
Patterns = Array("(Reg).*(Exp)", _
"Reg.*Exp", _
"Reg.*?Exp")
Call TestCapture(Patterns, Texts, True)
End Sub
Sub TestCapture(ByRef Patterns As Variant, ByRef Texts As Variant, _
Optional ByVal TimeDuration As Boolean = False)
' Patterns an array of patterns to be tested
' Texts an array of text to be matched against the patterns
' TimeDuration if True, record the average duration of the match
' Attempts to match each text against each pattern and reports on the result
' If TimeDuration is True, repeats the match 10,000,000 times and reports the
' average duration so the efficiency of different patterns can be determined
Dim CountCrnt As Long
Dim CountMax As Long
Dim InxM As Long
Dim InxS As Long
Dim Matches As MatchCollection
Dim PatternCrnt As Variant
Dim RegEx As New RegExp
Dim TimeEnd As Double
Dim TimeStart As Double
Dim SubMatchCrnt As Variant
Dim TextCrnt As Variant
With RegEx
.Global = True ' Find all matches
.MultiLine = False ' Match cannot extend across linebreak
.IgnoreCase = True
For Each PatternCrnt In Patterns
.Pattern = PatternCrnt
For Each TextCrnt In Texts
Debug.Print "==========================================="
Debug.Print " Pattern: """ & PatternCrnt & """"
Debug.Print " Text: """ & TidyTextForDspl(TextCrnt) & """"
If TimeDuration Then
CountMax = 10000000
TimeStart = Timer
Else
CountMax = 1
End If
For CountCrnt = 1 To CountMax
If Not .test(TextCrnt) Then
Debug.Print Space(12) & "Text does not match pattern"
Exit For
Else
Set Matches = .Execute(TextCrnt)
If CountCrnt = CountMax Then
TimeEnd = Timer
If TimeDuration Then
Debug.Print "Av Durat'n: " & Format((TimeEnd - TimeStart) / CountMax, "0.00000000")
End If
If Matches.Count = 0 Then
Debug.Print Space(12) & "Match but no captures"
Else
For InxM = 0 To Matches.Count - 1
Debug.Print "-------------------------------------------"
With Matches(InxM)
Debug.Print " Match: " & InxM + 1
Debug.Print " Value: """ & TidyTextForDspl(.Value) & """"
Debug.Print " Length: " & .Length
Debug.Print "FirstIndex: " & .FirstIndex
For InxS = 0 To .SubMatches.Count - 1
Debug.Print " SubMatch: " & InxS + 1 & " """ & _
TidyTextForDspl(.SubMatches(InxS)) & """"
Next
End With
Next InxM
End If
End If
End If
Next CountCrnt
Next TextCrnt
Next PatternCrnt
Debug.Print "==========================================="
End With
End Sub
Public Function TidyTextForDspl(ByVal Text As String) As String
' Tidy Text for dsplay by replacing white space with visible strings:
' Replace spaces by ‹s› or ‹n s›
' Replace line feed by ‹lf› or ‹n lf›
' Replace carriage return by ‹cr› or ‹n cr›
' Replace tab by ‹tb› or ‹n tb›
' Replace non-break space by ‹nbs› or {n nbs›
' Where n is a count if the character repeats
' 15Mar16 Coded
' 3Feb19 Replaced "{" (\x7B) and "}" (\x7D) by "‹" (\u2039) and "›" (\u203A)
' on the grounds that the angle quotation marks were not likely to
' appear in text to be displayed.
Dim InsStr As String
Dim InxWsChar As Long
Dim NumWsChar As Long
Dim PosWsChar As Long
Dim RetnVal As String
Dim WsCharCrnt As Variant
Dim WsCharValue As Variant
Dim WsCharDspl As Variant
WsCharValue = Array(" ", vbLf, vbCr, vbTab, Chr(160))
WsCharDspl = Array("s", "lf", "cr", "tb", "nbs")
RetnVal = Text
For InxWsChar = LBound(WsCharValue) To UBound(WsCharValue)
Do While True
PosWsChar = InStr(1, RetnVal, WsCharValue(InxWsChar))
If PosWsChar = 0 Then
Exit Do
End If
NumWsChar = 1
Do While Mid(RetnVal, PosWsChar + NumWsChar, 1) = WsCharValue(InxWsChar)
NumWsChar = NumWsChar + 1
Loop
If NumWsChar = 1 Then
InsStr = "‹" & WsCharDspl(InxWsChar) & "›"
Else
InsStr = "‹" & NumWsChar & WsCharDspl(InxWsChar) & "›"
End If
RetnVal = Mid(RetnVal, 1, PosWsChar - 1) & InsStr & Mid(RetnVal, PosWsChar + NumWsChar)
Loop
Next
TidyTextForDspl = RetnVal
End Function