解析正则表达式模式

3

有没有什么方法可以解析一个复杂的正则表达式模式(包含多个命名组、多个编号组和非捕获组),并报告每个组名或组号以及模式文本。

假设我有这样一个正则表达式模式:

  (?im)(?<x>\b[a-s03]+\b)(?-i)(?<a>\p{L}+?,(?<b>.+?:(?<c>.+?;(?<d>.+?(?:\d|sample-text|(\k'x'|sos30))))))

我喜欢提取以下内容:

  Named groups:
  x==>(?<x>\b[a-s03]+\b)
  a==>(?<a>\p{L}+?,(?<b>.+?:(?<c>.+?;(?<d>.+?(?:\d|sample-text|(\k'x'|sos30))))))
  b==>(?<b>.+?:(?<c>.+?;(?<d>.+?(?:\d|sample-text|(\k'x'|sos30)))))
  c==>(?<c>.+?;(?<d>.+?(?:\d|sample-text|(\k'x'|sos30))))
  d==>(?<d>.+?(?:\d|sample-text|(\k'x'|sos30)))

  Numbered groups:
  1==>(\k'x'|sos30)

  Non-capturing-groups:
  1st==>(?:\d|sample-text|(\k'x'|sos30))

该要求的目的:

我有一个复杂的正则表达式模式数据库。之前的程序员在准备这些复杂的模式时没有使用任何注释 [(?#...)],而且这些模式中也没有任何换行符。我必须修改这些模式并在其中使用注释。现在就像在干草堆里找针一样困难。我简单地无法使用正则表达式来实现这个目的。因此,我倾向于使用解析器来解决这个问题。

我尝试过的方法:

我尝试了GetGroupNamesGetGroupNumbers集合。我只能提取出名称/编号,但无法提取相应的文本模式。

我正在寻找非正则表达式解决方案/一些提示。


我不知道有任何现成的解决方案来解析正则表达式。虽然如果你简单地循环遍历该行,捕获开括号并查找相应的闭括号,那么制作类似的东西可能不应该非常困难。根据文本模式,您可以看到它是什么样的组。 - Patrickdev
@Patrickdev:感谢您抽出时间进行评论。实际上,我描述的示例非常简单,根本没有括号,而实际模式要复杂得多(大多数都是嵌套结构和许多带有转义字符的括号)。但是,是的,我同意您的建议准备一个新的解析器。但这将是重新发明轮子。如果没有其他解决方案,我肯定会考虑它。 - Cylian
看一下 http://www.regex101.com - 它可能会在这里有所帮助。 - Firas Dib
@Lindrian:感谢您的评论。但是,我确实需要一个RegEx解析器,通过它我将能够解析大量复杂的RegEx模式。个人使用Regexbuddy创建和编辑正则表达式模式,我认为这是必备的最佳工具,非常详细说明了这一点。但是,我不会手动操作。此外,您提到的网站非常“Pythonic”,我需要一个.NET兼容的正则表达式引擎 - Cylian
2个回答

3

对于这个问题,我们可以这样解决:

(?im)(?<x>\b[a-s03]+\b)(?-i)(?<a>\p{L}+?,(?<b>.+?:(?'c'.+?;(.+?(?:\d|sample-text|(\k'x'|sos30))))))

这是输出结果:
(0)<0>:     (?im)(?<x>\b[a-s03]+\b)(?-i)(?<a>\p{L}+?,(?<b>.+?:(?'c'.+?;(.+?(?:\d|sample-text|(\k'x'|sos30))))))
(1)<x>:     \b[a-s03]+\b
(2)<a>:     \p{L}+?,(?<b>.+?:(?'c'.+?;(.+?(?:\d|sample-text|(\k'x'|sos30))))
(3)<b>:     .+?:(?'c'.+?;(.+?(?:\d|sample-text|(\k'x'|sos30)))
(4)<c>:     .+?;(.+?(?:\d|sample-text|(\k'x'|sos30))
(5)<5>:     .+?(?:\d|sample-text|(\k'x'|sos30)
(6)<6>:     \k'x'|sos30

这是代码:

这是代码:

Imports System.Collections.Specialized
Module Module1
Public DictGroups As New OrderedDictionary
Public DictTrackers As New Dictionary(Of Integer, Boolean)
Public intGroups As Integer = 0
Public CommandGroup As Boolean = False
Sub Main()
    Dim regexToEval As String = "(?im)(?<x>\b[a-s03]+\b)(?-i)(?<a>\p{L}+?,(?<b>.+?:(?'c'.+?;(.+?(?:\d|sample-text|(\k'x'|sos30))))))"
    Dim curChar As String = ""
    DictGroups.Add(0, "(0)<0>: " & vbTab)
    DictTrackers.Add(0, True)
    For i = 1 To regexToEval.Length
        Dim iChar As String = regexToEval.Substring(i - 1, 1)
        If curChar <> "\" AndAlso iChar = ")" Then EndGroup()
        AddStrToTrackers(iChar)
        If curChar = "\" OrElse iChar <> "(" OrElse regexToEval.Length < i + 2 Then curChar = iChar : Continue For
        If regexToEval.Substring(i, 1) = "?" Then
            i += 1 : AddStrToTrackers("?")
            If regexToEval.Substring(i, 1) = ":" Then i += 1 : AddStrToTrackers(":") : curChar = ":" : Continue For
            Dim NameLength As Integer = 0
            If regexToEval.Substring(i, 1) = "<" Or regexToEval.Substring(i, 1) = "'" Then
                i += 1 : AddStrToTrackers(regexToEval.Substring(i - 1, 1))
                i += 1
                For x = i To regexToEval.Length
                    If regexToEval.Substring(x - 1, 1) = ">" Or regexToEval.Substring(x - 1, 1) = "'" Then
                        NameLength = x - i
                        Exit For
                    End If
                Next
            Else
                CommandGroup = True
                Continue For
            End If
            If NameLength > 0 Then
                Dim GroupName As String = regexToEval.Substring(i - 1, NameLength)
                i += NameLength : curChar = regexToEval.Substring(i - 1, 1) : AddStrToTrackers(GroupName & curChar)
                intGroups += 1
                DictGroups.Add(intGroups, "(" & DictGroups.Count & ")<" & GroupName & ">: " & vbTab)
                DictTrackers.Add(intGroups, True)
                Continue For
            End If
        End If
        curChar = iChar
        intGroups += 1
        DictGroups.Add(intGroups, "(" & DictGroups.Count & ")<" & intGroups.ToString & ">: " & vbTab)
        DictTrackers.Add(intGroups, True)
    Next
    Dim Output As String = MakeOutput()
End Sub

Private Function MakeOutput() As String
    Dim retString As String = String.Empty
    For i = 0 To DictGroups.Count - 1
        retString &= DictGroups(i) & vbCrLf
    Next
    Return retString
End Function

Public Sub EndGroup()
    If CommandGroup Then
        CommandGroup = False
        Exit Sub
    End If
    Dim HighestNum As Integer = 0
    For Each item In DictTrackers
        If Not item.Value Then Continue For
        If item.Key > HighestNum Then HighestNum = item.Key
    Next
    If HighestNum <> 0 Then DictTrackers(HighestNum) = False
End Sub

Public Sub AddStrToTrackers(ByVal addString As String)
    For Each item In DictTrackers
        If item.Value Then DictGroups(item.Key) &= addString
    Next
End Sub
End Module

唯一的区别是我没有捕获非捕获组或函数组。当然,这只是我在大约10分钟内编写的快速代码。但如果你需要的话,这是一个开始。我使用OrderedDictionary作为组号的键。如果你想在输出中包括非捕获组和函数组,你可以更改该结构。

非常感谢。我基本上是在寻找一些内置的“.NET”库。需要进行一些修改,但你的代码在这方面表现良好。 - Cylian

0

在 System.Text.RegularExpressions 命名空间中有一个 RegexParser 类(内部类),您可以使用私有反射调用它。我在我的 FxCopContrib 项目中一直在使用 示例实现

还有来自 Mono 项目的 RegexParser 实现,您可能可以利用它。

然后还有 Deveel 的 Regex 库


我正在寻找一种非正则表达式的解决方案。 - Victor Zakharov
这些都是非正则表达式的解决方案。建议使用平台使用的解析器来解析正则表达式,从而获得对象图,其中包含组成表达式的所有元素。这似乎正是OP所寻找的。 - jessehouwing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接