regex - 可以单独提取组的每个出现,但不能作为重复组
问题描述
我有许多文件,其中版本号作为名称的最后一部分。例如:
Xxxxx V2.txt
Xxxxx V2.3.txt
Xxxxx V2.10.txt
Xxxxx V2.10.3.txt
我使用正则表达式提取版本号的部分,以便我可以正确地对文件进行排序†,这样我就可以计算下一个版本号‡。
† 例如:V2.2 在 V2.10 之前,V2.2 在 V2.2.3 之前。
‡ 例如:V2.9 之后的下一个版本是 V2.10。
我可以单独处理每种样式的版本号,但我不能概括为所有样式创建一个正则表达式模式。
Text Pattern Value(s) extracted
Xxxxx V2.txt Xxxxx V(\d+)\.txt 2
Xxxxx V2.3.txt Xxxxx V(\d+)\.(\d+)\.txt 2 3
Xxxxx V2.10.3.txt Xxxxx V(\d+)\.(\d+)\.(\d+)\.txt 2 10 3
Xxxxx V2.10.3.txt Xxxxx V(\d+){\.(\d+)}*\.txt No match
我不明白为什么最后一个模式不适用于每种版本的版本号。任何指导表示赞赏。
回应评论的新部分
我希望我的正则表达式模式中有一个简单的错误,并且我的代码是无关紧要的。我整理了我的测试代码以创建:
Sub CtrlTestCapture()
Dim Patterns As Variant
Dim Texts As Variant
Texts = Array("Xxxxx V12.txt", _
"Xxxxx V12.3.txt", _
"Xxxxx V12.4.5.txt", _
"Xxxxx V12.4.5.3.txt")
Patterns = Array("Xxxxx V(\d+)\.txt", _
"Xxxxx V(\d+)\.(\d+)\.txt", _
"Xxxxx V(\d+)\.(\d+)\.(\d+)\.txt", _
"Xxxxx V(\d+){\.(\d+)}+\.txt", _
"Xxxxx V(\d+)(?:\.(\d+))?(?:\.(\d+))?\.txt" , _
"Xxxxx V(\d+)(\.(\d+))*\.txt")
Call TestCapture(Patterns, Texts)
End Sub
Sub TestCapture(ByRef Patterns As Variant, ByRef Texts As Variant)
Dim InxM As Long
Dim InxS As Long
Dim Matches As MatchCollection
Dim PatternCrnt As Variant
Dim RegEx As New RegExp
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: """ & TextCrnt & """"
If Not .test(TextCrnt) Then
Debug.Print Space(12) & "Text does not match pattern"
Else
Set Matches = .Execute(TextCrnt)
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: """ & .Value & """"
Debug.Print " Length: " & .Length
Debug.Print "FirstIndex: " & .FirstIndex
For InxS = 0 To .SubMatches.Count - 1
Debug.Print " SubMatch: " & InxS + 1 & " """ & .SubMatches(InxS) & """"
Next
End With
Next
End If
End If
Next
Next
Debug.Print "==========================================="
End With
End Sub
使用此代码,Wiktor Stribiżew 正则表达式模式比我的杂乱代码产生了更好的结果。我将不得不查看我的原始代码以找到我的错误。使用此代码,Wiktor Stribiżew 正则表达式模式的输出为:
===========================================
Pattern: "Xxxxx V(\d+)(?:\.(\d+))?(?:\.(\d+))?\.txt"
Text: "Xxxxx V12.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.txt"
Length: 13
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 ""
SubMatch: 3 ""
===========================================
Pattern: "Xxxxx V(\d+)(?:\.(\d+))?(?:\.(\d+))?\.txt"
Text: "Xxxxx V12.3.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.3.txt"
Length: 15
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 "3"
SubMatch: 3 ""
===========================================
Pattern: "Xxxxx V(\d+)(?:\.(\d+))?(?:\.(\d+))?\.txt"
Text: "Xxxxx V12.4.5.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.4.5.txt"
Length: 17
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 "4"
SubMatch: 3 "5"
===========================================
Pattern: "Xxxxx V(\d+)(?:\.(\d+))?(?:\.(\d+))?\.txt"
Text: "Xxxxx V12.4.5.3.txt"
Text does not match pattern
===========================================
这具有固定数量的捕获,而不是我尝试的可变数量。我还必须弄清楚如何扩展它以处理“12.4.5.3”,这是我见过的最复杂的版本号样式。这并不完美,但绝对是对我当前解决方法的改进。您正在使用我不认识的正则表达式字符,因此我需要仔细研究。
使用上面的代码,Tiw 正则表达式模式产生了这个输出:
===========================================
Pattern: "Xxxxx V(\d+)(\.(\d+))*\.txt"
Text: "Xxxxx V12.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.txt"
Length: 13
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 ""
SubMatch: 3 ""
===========================================
Pattern: "Xxxxx V(\d+)(\.(\d+))*\.txt"
Text: "Xxxxx V12.3.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.3.txt"
Length: 15
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 ".3"
SubMatch: 3 "3"
===========================================
Pattern: "Xxxxx V(\d+)(\.(\d+))*\.txt"
Text: "Xxxxx V12.4.5.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.4.5.txt"
Length: 17
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 ".5"
SubMatch: 3 "5"
===========================================
Pattern: "Xxxxx V(\d+)(\.(\d+))*\.txt"
Text: "Xxxxx V12.4.5.3.txt"
-------------------------------------------
Match: 1
Value: "Xxxxx V12.4.5.3.txt"
Length: 19
FirstIndex: 0
SubMatch: 1 "12"
SubMatch: 2 ".3"
SubMatch: 3 "3"
===========================================
也就是说,它似乎总是捕捉到:第一部分,包括点的最后部分和没有点的最后部分。有希望但不完全在那里。
第 3 部分
我忽略了对我寻求的结果进行明确解释的要求。
我在所有重要文件上都使用版本号。我从其他人那里收到包含版本号的文件,其中一些比我的复杂得多。我总是将版本号作为文件名的最后一部分,并且在版本号之前总是有一个“V”。如果我收到不符合我的格式的文件,我会重命名它们。所以我的文件名称如下:
- Xxxxx VN.xxx
- Xxxxx VN.N.xxx
- Xxxxx VN.NNxxx
- Xxxxx VN.NNNxxx
我希望将 Ns 提取到可变长度数组或集合中,以便可以使用通用例程处理它们。事实上,我已经有了那些通用的例程。这些例程依赖于一些提取 Ns 的杂乱 VBA 代码。我认为使用 Regex 可以让我整理我的代码。
解决方案
试试这个正则表达式:
V(\d+(?:\.\d+)*)\.txt$
所需的版本在 Group 1 中捕获。您可以进一步拆分 Group 1 的内容.
代码:
Dim objReg, strFile, objMatches, strVersion, arrVersion
strFile = "Xxxxx V2.3.txt"
Set objReg = New RegExp
objReg.Global = True
objReg.Multiline = True
objReg.Pattern = "V(\d+(?:\.\d+)*)\.txt$"
If objReg.Test(strFile) Then
Set objMatches = objReg.Execute(strFile)
strVersion = objMatches.item(0).submatches.item(0) 'To get the full version number
arrVersion = Split(strVersion,".") 'To get each number in the version(stored in array)
End If
正则表达式解释:
V(\d+(?:\.\d+)*)\.txt$
V
- 火柴V
(\d+(?:\.\d+)*)
- 匹配 1+ 次出现的数字。匹配尽可能多的数字后,匹配 0 次或多次出现的点,.
后跟 1 位以上的数字。整个匹配记录在第 1 组中,是您所需的版本号\.txt
- 火柴.txt
$
- 断言行尾。
推荐阅读
- perl - 将 perl 中的字符串截断为带有尾随省略号的子字符串
- r - 如何使用 R 中的最大公因数创建一个函数来查找整数向量的最小公倍数?
- node.js - 在快速应用程序中查找未使用的路线或代码以删除死代码
- python - 使用python解读图像
- php - 如何用php在Jpgraph中设置虚线
- ansible - Ansible set_fact 正在覆盖项目
- python-3.x - 由于 tex 错误“RuntimeError:无法使用 tex 处理字符串,因为找不到 dvipng”而无法并行注释文本
- javascript - 删除条形图 ZingChart 上的空间
- php - 怎么做for函数是基于id的,有数据库里的数据
- r - 在 RGoogleAnalytics 中刷新令牌