代码之家  ›  专栏  ›  技术社区  ›  Tony Dallimore

可以单独提取组的每个匹配项,但不能作为重复组提取

  •  1
  • Tony Dallimore  · 技术社区  · 7 年前

    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 Stribiew regex模式产生的结果比我不整洁的代码要好。我将不得不检查我的原始代码以找到我的错误。使用此代码,Wiktor Stribiew regex模式的输出为:

    ===========================================
       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"
    ===========================================
    

    第三部分

    我忽略了对我寻求的结果作出明确解释的要求。

    我在所有重要文件上使用版本号。我收到其他人的文件,其中包括版本号,其中一些比我的要复杂得多。我总是将版本号作为文件名的最后一部分,并且在版本号之前总是有一个V。如果我收到的文件不符合我的格式,我会重新命名它们。因此,我有一些文件的名称如下:

    • Xxxxx VN.xxx
    • Xxxxx VN.N.N.xxx
    • Xxxxx VN.N.N.xxx

    我希望将Ns提取到可变长度数组或集合中,以便使用通用例程处理它们。事实上,我已经有了这些通用程序。这些例程依赖于提取Ns的一些凌乱的VBA代码。我认为使用正则表达式可以让我整理代码。

    2 回复  |  直到 7 年前
        1
  •  3
  •   Gurmanjot Singh    7 年前

    试试这个正则表达式:

    V(\d+(?:\.\d+)*)\.txt$
    

    所需版本在组1中捕获。您可以使用 .

    Click for Demo

    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
    • (\d+(?:\.\d+)*) -匹配数字的1+个匹配项。在匹配尽可能多的数字后,匹配0个或更多出现的点 后跟1+个数字。整个匹配在第1组中捕获,并且是您所需的版本号
    • \.txt -火柴 .txt
    • $ -断言行的结尾。
        2
  •  1
  •   Ryan Wildry    7 年前

    如果您愿意,这里有一个非正则表达式的解决方案。您可以将版本号转换为数字,然后对其进行排序。

    Sub GetOrderedList()
        Dim Texts               As Variant
        Dim FileName            As String
        Dim FileArrayList       As Object
        Dim Item                As Variant
    
        Set FileArrayList = CreateObject("System.Collections.ArrayList")
    
        Texts = Array("Xxxxx V12.txt", _
                      "Xxxxx V12.3.txt", _
                      "Xxxxx V12.4.5.txt", _
                      "Xxxxx V12.4.5.3.txt")
    
    
        For i = LBound(Texts) To UBound(Texts)
            'You get use the FileSystemObject to make this a bit easier
            FileName = Replace(Replace(Split(Texts(i), " ")(UBound(Split(Texts(i), " "))), "V", ""), ".txt", "")
            PeriodPosition = InStr(1, FileName, ".")
    
            'Convert to a number, then sort
            If PeriodPosition > 0 Then FileName = Left$(FileName, PeriodPosition) & Replace(FileName, ".", "0", PeriodPosition + 1)
            FileArrayList.Add FileName
        Next
    
        'Sort
        FileArrayList.Sort
    
        'Print out, ascending order
        For Each Item In FileArrayList
            Debug.Print Item
        Next
    
    End Sub