正则表达式表达挑战

时间:2009-09-01 15:55:59

标签: c# .net vb.net regex

有人可以使用正则表达式:

  1. 找到以[%并以%结尾]
  2. 开头的块
  3. 在该块中用以下内容替换所有xml特殊字符:
    &安培; QUOT; &安培;者; &安培; LT; &安培; GT; &安培;放大器;
  4. 将所有内容保留在<%=%>之间或<%#%>除了确保在<%#或<%=之前和%>之前有空格例如<%= Integer.MaxValue%>应该成为<%= Integer.MaxValue%>
  5. 源:

    [% 'test' <mtd:ddl id="asdf" runat="server"/> & <%= Integer.MaxValue% > %]
    

    结果:

    &apos;test&apos; &lt;mtd:ddl id=&quot;asdf&quot; runat=&quot;server&quot;/&gt; &amp; <%= Integer.MaxValue %>
    

3 个答案:

答案 0 :(得分:2)

使用了2个正则表达式。第一个匹配一般形式,第二个来处理内部管道。

对于XML编码,我在System.Security中使用了一个不起眼的小方法:SecurityElement.Escape Method。我完全限定了以下代码中的重点。另一种选择是使用HttpUtility.HtmlEncode method但可能涉及对System.Web的引用,具体取决于您使用它的位置。

string[] inputs = { @"[% 'test' <mtd:ddl id=""asdf"" runat=""server""/> & <%= Integer.MaxValue %> %]",
    @"[% 'test' <mtd:ddl id=""asdf"" runat=""server""/> & <%=Integer.MaxValue %> %]",
    @"[% 'test' <mtd:ddl id=""asdf"" runat=""server""/> & <%# Integer.MaxValue%> %]",
    @"[% 'test' <mtd:ddl id=""asdf"" runat=""server""/> & <%#Integer.MaxValue%> %]",
};
string pattern = @"(?<open>\[%)(?<content>.*?)(?<close>%])";
string expressionPattern = @"(?<content>.*?)(?<tag><%(?:[=#]))\s*(?<expression>.*?)\s*%>";

foreach (string input in inputs)
{
    string result = Regex.Replace(input, pattern, m =>
        m.Groups["open"].Value +
        Regex.Replace(m.Groups["content"].Value, expressionPattern,
            expressionMatch =>
            System.Security.SecurityElement.Escape(expressionMatch.Groups["content"].Value) +
            expressionMatch.Groups["tag"].Value + " " +
            expressionMatch.Groups["expression"].Value +
            " %>"
        ) +
        m.Groups["close"].Value
    );

    Console.WriteLine("Before: {0}", input);
    Console.WriteLine("After: {0}", result);
}

结果:

Before: [% 'test' <mtd:ddl id="asdf" runat="server"/> & <%= Integer.MaxValue %> %]
After: [% &apos;test&apos; &lt;mtd:ddl id=&quot;asdf&quot; runat=&quot;server&quot;/&gt; &amp; <%= Integer.MaxValue %> %]
Before: [% 'test' <mtd:ddl id="asdf" runat="server"/> & <%=Integer.MaxValue %> %]
After: [% &apos;test&apos; &lt;mtd:ddl id=&quot;asdf&quot; runat=&quot;server&quot;/&gt; &amp; <%= Integer.MaxValue %> %]
Before: [% 'test' <mtd:ddl id="asdf" runat="server"/> & <%# Integer.MaxValue%> %]
After: [% &apos;test&apos; &lt;mtd:ddl id=&quot;asdf&quot; runat=&quot;server&quot;/&gt; &amp; <%# Integer.MaxValue %> %]
Before: [% 'test' <mtd:ddl id="asdf" runat="server"/> & <%#Integer.MaxValue%> %]
After: [% &apos;test&apos; &lt;mtd:ddl id=&quot;asdf&quot; runat=&quot;server&quot;/&gt; &amp; <%# Integer.MaxValue %> %]

编辑:如果您不关心在最终结果中保留开启/关闭[%%],请将模式更改为:

string pattern = @"\[%(?<content>.*?)%]";

然后务必删除对m.Groups["open"].Valuem.Groups["close"].Value的引用。

答案 1 :(得分:1)

private void button1_Click(object sender, EventArgs e)
        {
            Regex reg = new Regex(@"\[%(?<b1>.*)%\]");
            richTextBox1.Text= reg.Replace(textBox1.Text, new MatchEvaluator(f1));
        }

        static string f1(Match m)
        {
            StringBuilder sb = new StringBuilder();
            string[] a = Regex.Split(m.Groups["b1"].Value, "<%[^%>]*%>");
            MatchCollection col = Regex.Matches(m.Groups["b1"].Value, "<%[^%>]*%>");
            for (int i = 0; i < a.Length; i++)
            {
                sb.Append(a[i].Replace("&", "&amp;").Replace("'", "&apos;").Replace("\"", "&quot;").Replace("<", "&lt;").Replace(">", "&gt;"));
                if (i < col.Count)
                    sb.Append(col[i].Value);
            }
            return sb.ToString();
        }

测试1:

[% 'test' <mtd:ddl id="asdf" runat="server"/> & <%= Integer.MaxValue%> fdas<% hi%> 321%]

结果:

 &apos;test&apos; &lt;mtd:ddl id=&quot;asdf&quot; runat=&quot;server&quot;/&gt; &amp; <%= Integer.MaxValue%> fdas<% hi%> 321

答案 2 :(得分:0)

我认为在不使用RegEx的情况下代码将会清晰。我倾向于为规范的每一行编写一个单独的方法(和单元测试),然后将它们链接在一起。

另请参阅“When not to use Regex in C# (or Java, C++ etc)"