1

我需要匹配双花括号之间的所有字符,但我需要能够在一个大字符串中找到多个匹配项。

我一直在使用这个 RegEx 测试器,因为我在 C# 中这样做:http: //derekslager.com/blog/posts/2007/09/a-better-dotnet-regular-expression-tester.ashx 另外,我有“ SingleLine”因为我想要而被选中。匹配\n

这是我正在匹配的字符串的示例:

<div class="nest-1-2">
    <dl>
    <dt>Type:</dt>
    <dd>{{(Entity)Field Name.separator(, ) > [:Name:]}}</dd>
    <dt>At:</dt>
    <dd>{{(Entity)Field Name > [:Name:]}}</dd>
    <dt>Team:</dt>
    <dd>{{(Entity)Field Name.separator(, ) > [:First Name:] [:Last Name:]}}</dd>
    </dl>
</div>

这是我正在使用的正则表达式:

\{\{(?<field>[^>]*)?[ > ]?(?<looptemplate>[^\}\}].*)?\}\}

我遇到的问题是我希望所有内容都匹配到下一个 }} 的所有文本,这是匹配最后一个而不是下一个。所以我得到了 1 场比赛,这是从第一场{{到最后一场比赛,}}我尝试使用负面展望,(?!\}\})但这似乎对我不起作用。不幸的是,[^\}\}]不匹配两个花括号,它只匹配一个。

我不是一个正则表达式的菜鸟,但这个真的让我很着迷。我已经四处寻找答案,所以现在我希望有人可以帮助我。

我真的很感谢专家的任何帮助。

4

4 回答 4

5

一些东西:

  1. 您正在使用?包含*. 意思是“ *0次或多次”,所以基本上内容已经是可选的。使用?不会做任何事情。

    \{\{(?<field>[^>]*)[ > ]?(?<looptemplate>[^\}\}].*)\}\}
    
  2. [ > ]匹配1 个字符。空格或>. 您可能的意思是(?: > )(匹配" > "(忽略引号,否则 SO 不会呈现空格)并将其组合在一起。

    \{\{(?<field>[^>]*)(?: > )?(?<looptemplate>[^\}\}].*)\}\}
    
  3. [^\}\}]是一样的[^\}]。否定字符类不适用于字符串,它们仅适用于内部的每个单独字符,因此多次编写一个不会改变任何内容。我想这就是为什么你尝试了消极的前瞻。这是正确的,但您需要检查重复的每个字符的条件。否则,您只检查一次,即您的looptemplate不是以 开头,\}\}但随后您以 . 开火.*。因此,将分组.和前瞻放在一起:

    \{\{(?<field>[^>]*)(?: > )?(?<looptemplate>(?:(?!\}\}).)*)\}\}
    
  4. (?: > )是可选的,所以如果你有一些{{...}}不包含它的部分(只有field部分你会遇到与以前相同的问题,只是这次使用[^>]. 在这里也包括前瞻:

    \{\{(?<field>(?:(?!\}})[^>])*)(?: > )?(?<looptemplate>(?:(?!\}\}).)*)\}\}
    

顺便说一句,使用否定字符类或前瞻的替代方法是使用不贪婪的重复。如果您可以使用否定字符类,那通常是可取的,因为它同样具有可读性,但通常比 ungreedy 修饰符更有效,因为它不需要回溯。在您的情况下,您必须使用前瞻(因为您不想跳过两个连续字符的模式,而不仅仅是一个字符)。在这种情况下,前瞻可能会抵消避免回溯带来的性能提升,而且前瞻通常不太可读。所以你可能只想在这里进行不贪婪的重复(在重复量词后面加上?):

\{\{(?<field>(?:(?!\}})[^>])*)(?: > )?(?<looptemplate>.*?)\}\}

请注意,您不能使用不贪婪的重复,field因为,(?: > )是可选的。这将导致为field空和其他所有内容(包括可能" > "与 匹配looptemplate除非您将 与>一起包含到可选组中looptemplate

\{\{(?<field>[^>]*?)(?: > (?<looptemplate>.*?))?\}\}

最后一点。这只是一个口味问题,但让我向您介绍另一种形式的逃避。许多元字符在字符类中时不是元字符(只有、 和]仍然-是)。因此,您可以将元字符包装在字符类中以对其进行转义:^\

[{][{](?<field>[^>]*?)(?: > (?<looptemplate>.*?))?[}][}]

正如我所说,这只是一个建议,但对于大多数字符,我发现这比使用反斜杠更具可读性。

于 2012-12-12T21:56:50.997 回答
2

另外,我检查了“SingleLine”,因为我想要 . 匹配\n

如果您取消勾选“单行”,它将起作用。所以很明显你.是问题所在。一个简单的解决方案是使用.*?而不是.*尽可能多地非贪婪地选择它(而不是尽可能地贪婪地选择)。另一种解决方案是用.更具体的东西代替,比如负面的前瞻,因为你可能不想匹配{{它内部的另一个(甚至}})。但在这种情况下,非贪婪的解决方案要容易得多。

您可能还应该更改字段字符类的乘数,这样它就不会匹配已经是循环模板一部分的内容。

另请注意,这[ > ]是一个将选择空格或>. 所以它不会选择" > ". 如果你想这样,只需去掉括号:

\{\{(?<field>[^>]*?)? > (?<looptemplate>[^}].*?)?\}\}

在您的情况下,由于您可能希望将 looptemplate 的东西设为可选,您可能希望这样做,但使用非捕获组:

\{\{(?<field>[^>]*?)?(?: > (?<looptemplate>[^}].*?))?\}\}

还有最后一点;如果您希望.匹配换行符,最好在必要时提供一个示例。

(好的,另一个注意事项,正如 m.buettner 在他的回答中正确提到的那样,字符类只需要提及每个字符一次;此外,您不需要在字符类中转义大括号,所以这一切都简化为[^}]

于 2012-12-12T22:02:59.517 回答
0

那这个呢:

\{\{.*?\}\}

.*?类似于.*但采用惰性匹配,而不是贪婪。这意味着它会停止匹配,并尝试尽快继续匹配正则表达式的其余部分,而不是贪婪匹配,它会在继续使用正则表达式的其余部分之前尝试尽可能多的消耗。

因此,适用于:“{{this}} and that}}”

\{\{.*?\}\}匹配“{{this}}”

\{\{.*\}\}匹配“{{this}} and that}}”

于 2012-12-12T21:54:58.177 回答
0

编辑开始:

好的,所以我更改了文本文件....

<div class="nest-1-2">
    <dl>
    <dt>Type:</dt>
    <dd>{{(Entity)Field Name.separator(, ) > [:Name:]
    foo came up
    boo is here too}}</dd>
    <dt>At:</dt>
    <dd>{{(Entity)Field Name > [:Name:]}}</dd>
    <dt>Team:</dt>
    <dd>{{(Entity)Field Name.separator(, ) > [:First Name:] [:Last Name:]}}</dd>
    </dl>
</div>

然后我在 Regex 新构造函数中添加了一个参数......具有讽刺意味的是,该选项是“SingleLine”

System.Text.RegularExpressions.Regex Y = new System.Text.RegularExpressions.Regex("{{(.*?)\\}}", System.Text.RegularExpressions.RegexOptions.Singleline);

编辑结束………………

我将您的示例字符串复制并粘贴到一个平面文本文件中以进行测试....

namespace a
{
    class Program
    {
        static void Main(string[] args)
        {
            string X = System.IO.File.ReadAllText("C:\\Users\\rnirnberger\\Documents\\a.txt");
            System.Text.RegularExpressions.Regex Y = new System.Text.RegularExpressions.Regex("{{(.*?)\\}}");
            System.Text.RegularExpressions.MatchCollection Z = Y.Matches(X);
            foreach (System.Text.RegularExpressions.Match match in Z)
            {
                Console.WriteLine(match.Value);

                //If you want to strip out the double-braces
                //↓↓↓↓

                //Console.WriteLine(match.Value.Replace("{{", "").Replace("}}", ""));
            }
        }
    }
于 2012-12-12T21:57:10.940 回答