VB.Net 匹配并替换字符串中多个重叠括号组的内容

发布于 2024-11-14 01:43:34 字数 1105 浏览 2 评论 0原文

我正在使用 vb.net 来解析我自己的基本脚本语言,示例如下。我在尝试处理两种不同类型的嵌套括号时有点困难。

Assuming name = Sam
Assuming timeFormat = hh:mm:ss
Assuming time() is a function that takes a format string but  
         has a default value and returns a string.


Hello [[name]], the time is [[time(hh:mm:ss)]].
Result: Hello Sam, the time is 19:54:32.

The full time is [[time()]].
Result: The full time is 05/06/2011 19:54:32.

The time in the format of your choice is [[time([[timeFormat]])]].
Result: The time in the format of your choice is 19:54:32.

理论上我可以完全改变脚本的语法,但我不愿意。它的设计是为了启用不带引号的字符串,因为它将包含在 XML 文件中,而该上下文中的引号会变得混乱,并且很容易出现错误和可读性问题。如果失败,我可以使用引号以外的东西重新设计来标记字符串,但我宁愿使用这种方法。

最好,除非有其他我不知道的方法,否则我想使用正则表达式来执行此操作。我知道标准正则表达式并不能真正做到这一点,但我相信使用 vb.net 中的 MatchEvaluators 和某种形式的基于递归的替换是可能的。然而,在最后一天左右的时间里,我一直无法集中注意力,可能是因为这非常困难,可能是因为我病了,也可能是因为我很胖。

我确实有以下部分正则表达式。

Detecting the parentheses: (\w*?)\((.*?)\)(?=[^\(+\)]*(\(|$))
Detecting the square brackets: \[\[(.*?)\]\](?=[^\[+\]]*(\[\[|$))

我真的很感谢这方面的一些帮助,因为它目前阻碍了我项目的其余部分。抱歉,如果我啰嗦太多或没有提供足够的细节,这是我在这里的第一个问题。

I am using vb.net to parse my own basic scripting language, sample below. I am a bit stuck trying to deal with the 2 separate types of nested brackets.

Assuming name = Sam
Assuming timeFormat = hh:mm:ss
Assuming time() is a function that takes a format string but  
         has a default value and returns a string.


Hello [[name]], the time is [[time(hh:mm:ss)]].
Result: Hello Sam, the time is 19:54:32.

The full time is [[time()]].
Result: The full time is 05/06/2011 19:54:32.

The time in the format of your choice is [[time([[timeFormat]])]].
Result: The time in the format of your choice is 19:54:32.

I could in theory change the syntax of the script completely but I would rather not. It is designed like this to enable strings without quotes because it will be included in an XML file and quotes in that context were getting messy and very prone to errors and readability issues. If this fails I could redesign using something other than quotes to mark out strings but I would rather use this method.

Preferably, unless there is some other way I am not aware of, I would like to do this using regex. I am aware that the standard regex is not really capable of this but I believe this is possible using MatchEvaluators in vb.net and some form of recursion based replacing. However I have not been able to get my head around it for the last day or so, possibly because it is hugely difficult, possibly because I am ill, or possibly because I am plain thick.

I do have the following regex for parts of it.

Detecting the parentheses: (\w*?)\((.*?)\)(?=[^\(+\)]*(\(|$))
Detecting the square brackets: \[\[(.*?)\]\](?=[^\[+\]]*(\[\[|$))

I would really appreciate some help with this as it is holding the rest of my project back at the moment. And sorry if I have babbled on too much or not put enough detail, this is my first question on here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沫雨熙 2024-11-21 01:43:34

这是一个小示例,可以帮助您迭代多个匹配/组/捕获。我意识到我正在发布 C# 代码,但您可以轻松地将其转换为 VB.Net

//these two may be passed in as parameters:
string tosearch;//the string you are searching through
string regex;//your pattern to match
//...
Match m;
CaptureCollection cc;
GroupCollection gc;

Regex r = new Regex(regex, RegexOptions.IgnoreCase);
m = r.Match(tosearch);
gc = m.Groups;
Debug.WriteLine("Number of groups found = " + gc.Count.ToString());

// Loop through each group.
for (int i = 0; i < gc.Count; i++)
{
  cc = gc[i].Captures;
  counter = cc.Count;
  int grpnum = i + 1;
  Debug.WriteLine("Scanning group: " + grpnum.ToString() );

  // Print number of captures in this group.
  Debug.WriteLine("  Captures count = " + counter.ToString());

  if (cc.Count >= 1)
  {
    foreach (Capture cap in cc)
    {
      Debug.WriteLine(string.format("  Capture found: {0}", cap.ToString()));
    }
  }
}

Here's a little sample which might help you iterate through several matches/groups/captures. I realize that I am posting C# code, but it would be easy for you to convert that into VB.Net

//these two may be passed in as parameters:
string tosearch;//the string you are searching through
string regex;//your pattern to match
//...
Match m;
CaptureCollection cc;
GroupCollection gc;

Regex r = new Regex(regex, RegexOptions.IgnoreCase);
m = r.Match(tosearch);
gc = m.Groups;
Debug.WriteLine("Number of groups found = " + gc.Count.ToString());

// Loop through each group.
for (int i = 0; i < gc.Count; i++)
{
  cc = gc[i].Captures;
  counter = cc.Count;
  int grpnum = i + 1;
  Debug.WriteLine("Scanning group: " + grpnum.ToString() );

  // Print number of captures in this group.
  Debug.WriteLine("  Captures count = " + counter.ToString());

  if (cc.Count >= 1)
  {
    foreach (Capture cap in cc)
    {
      Debug.WriteLine(string.format("  Capture found: {0}", cap.ToString()));
    }
  }
}
半城柳色半声笛 2024-11-21 01:43:34

这是我为此编写的代码的稍微简化的版本。感谢大家的帮助,抱歉我之前忘记发帖了。如果您有任何疑问或任何问题,请随时询问。

Function processString(ByVal scriptString As String)
    ' Functions
    Dim pattern As String = "\[\[((\w+?)\((.*?)\))(?=[^\(+\)]*(\(|$))\]\]"
    scriptString = Regex.Replace(scriptString, pattern, New MatchEvaluator(Function(match) processFunction(match)))

    ' Variables
    pattern = "\[\[([A-Za-z0-9+_]+)\]\]"
    scriptString = Regex.Replace(scriptString, pattern, New MatchEvaluator(Function(match) processVariable(match)))
    Return scriptString
End Function

Function processFunction(ByVal match As Match)
    Dim nameString As String = match.Groups(2).Value
    Dim paramString As String = match.Groups(3).Value
    paramString = processString(paramString)
    Select Case nameString
        Case "time"
            Return getLocalValueTime(paramString)
        Case "math"
            Return getLocalValueMath(paramString)
    End Select
    Return ""
End Function

Function processVariable(ByVal match As Match)
    Try
        Return moduleDictionary("properties")("vars")(match.Groups(1).Value)
    Catch ex As Exception
    End Try
End Function

Here is a slightly simplified version of the code I wrote for this. Thanks for the help everyone and sorry I forgot to post this before. If you have any questions or anything feel free to ask.

Function processString(ByVal scriptString As String)
    ' Functions
    Dim pattern As String = "\[\[((\w+?)\((.*?)\))(?=[^\(+\)]*(\(|$))\]\]"
    scriptString = Regex.Replace(scriptString, pattern, New MatchEvaluator(Function(match) processFunction(match)))

    ' Variables
    pattern = "\[\[([A-Za-z0-9+_]+)\]\]"
    scriptString = Regex.Replace(scriptString, pattern, New MatchEvaluator(Function(match) processVariable(match)))
    Return scriptString
End Function

Function processFunction(ByVal match As Match)
    Dim nameString As String = match.Groups(2).Value
    Dim paramString As String = match.Groups(3).Value
    paramString = processString(paramString)
    Select Case nameString
        Case "time"
            Return getLocalValueTime(paramString)
        Case "math"
            Return getLocalValueMath(paramString)
    End Select
    Return ""
End Function

Function processVariable(ByVal match As Match)
    Try
        Return moduleDictionary("properties")("vars")(match.Groups(1).Value)
    Catch ex As Exception
    End Try
End Function
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文