Может извлекать каждое вхождение группы индивидуально, но не как повторяющуюся группу - PullRequest
0 голосов
/ 14 января 2019

У меня есть много файлов с номерами версий в качестве последней части имени. Например:

Xxxxx V2.txt
Xxxxx V2.3.txt
Xxxxx V2.10.txt
Xxxxx V2.10.3.txt

Я использую Regex для извлечения частей номера версии, чтобы я мог правильно упорядочить файлы † и чтобы я мог рассчитать следующий номер версии ‡.

† Например: V2.2 предшествует V2.10, а V2.2 предшествует V2.2.3.

‡ Например: следующая версия после V2.9 - V2.10.

Я могу обрабатывать каждый стиль номера версии отдельно, но не могу обобщить, чтобы создать один шаблон Regex для всех стилей.

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», который является самым сложным стилем номера версии, который я когда-либо видел. Это не идеально, но это определенно улучшение моего текущего решения. Вы используете символы Regex, которые я не узнаю, поэтому мне нужно внимательно изучить это.

С помощью приведенного выше кода шаблон регулярного выражения 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.N.N.xxx
  • Xxxxx VN.N.N.N.xxx

Я хочу извлечь Ns в массив переменной длины или коллекцию, чтобы я мог обработать их с помощью стандартных процедур. На самом деле, у меня уже есть эти общие процедуры. Эти процедуры основаны на некотором грязном коде VBA, который извлекает Ns. Я думал, что использование Regex позволит мне привести в порядок свой код.

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Вот решение без регулярных выражений, если вы предпочитаете. Вы можете преобразовать номер версии в число, а затем отсортировать его.

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
0 голосов
/ 14 января 2019

Попробуйте это регулярное выражение:

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

Требуемая версия фиксируется в группе 1. Вы можете дополнительно разделить содержимое группы 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

Regex Объяснение:

  • V(\d+(?:\.\d+)*)\.txt$
  • V - совпадения V
  • (\d+(?:\.\d+)*) - соответствует 1+ появлению цифры. После сопоставления максимально возможного количества цифр сопоставьте 0 или более вхождений точки ., за которой следуют 1+ цифр. Весь этот матч фиксируется в группе 1 и является вашим требуемым номером версии
  • \.txt - совпадения .txt
  • $ - устанавливает конец строки.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...