代码之家  ›  专栏  ›  技术社区  ›  citronas

如何调整regex以使用多行和更复杂的文本?

  •  1
  • citronas  · 技术社区  · 14 年前

    背景:我写了一个小库,它可以从字符串创建ASP.NET控件。

    样本文本 :

    Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et 
    {{asp:hyperlink|NavigateUrl="/faq.aspx";Text="FAQ";}}
    {{codesample|Text="FAQ";}}
    accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur 
    

    我得到了初步的帮助 here . 我通过一些反射来扩展代码,以获得完全的灵活性,从而能够呈现WebControls和UserControls。到目前为止,对于我测试过的每个用户控件,都可以正常工作。我现在面临的问题是,我的属性键值的解析不够灵活,无法支持任意多行内容。

    这是我用于字符串操作的代码的一部分:

    substring = substring.Replace("\\"", "\""); //substring is the string containing lore ipsum
    substring = substring.Replace(""", "\"");
    Regex r = new Regex("{{(?<single>([a-z0-9:]*))\\|((?<pair>([a-z0-9:]*=\"[a-z0-9.:/?_~=]*\";))*)}}", RegexOptions.Singleline | RegexOptions.IgnoreCase);
    Match m = r.Match(substring);
    if (m.Success)
    {
        Dictionary<string, string> properties = new Dictionary<string, string>();
        foreach (Capture cap in m.Groups["pair"].Captures)
        {
            string key = cap.ToString().Substring(0, cap.ToString().IndexOf("="));
            if (!properties.ContainsKey(key))
            {
                string value = cap.ToString().Substring(cap.ToString().IndexOf("=\"") + 2);
                value = value.Substring(0, value.Length - 2);
                properties.Add(key, value);
            }
        }
        MethodInfo dynamicRenderControl = null;
        String controlString = m.Groups["single"].Value.ToLower();
    }
    

    (字符串来自数据库。它以前是在我的CMS中设置的。我留下了获取foo bar=“foo2”;组的代码

    这就是regex所做的: 例子:

    {{asp:hyperlink|NavigateUrl="/faq.aspx";Text="FAQ";}}
    

    它将“asp:hyperlink”解析为m.groups[“single”]。它是映射到特定控件类型所需的字符串。

    在“”之后,我有将捕获到m.groups[“pair”]捕获中的属性列表。

    这一切都很好,但不适用于多行文本或更复杂的文本。 例如。

    {{codesample|Text="using System.Text;<br />\r\nusing System.Bla;";}}
    

    这就是我的代码被破坏的地方。 问题:
    如何调整regex使其适用于多行文本,该文本以\“开头,以\”结尾,尽管该文本中可能也有\“内容”?或者这在regex中是不可能的?

    编辑 我一直在想。用regex是不可能实现我想要的,因为文本中的“a”会自动破坏代码。我将外部熟食器切换为XML使用的CDATA语法。 Wikientry for CDATA

    "<![CDATA[This is my content]]>";
    

    这意味着每个条目如下所示:

    {{codesample|Text="<![CDATA[this is text on the first line<br />\r\nthis is text on the second line]]>";}}
    

    其中值的开头是

    "<![CDATA[
    

    最后

    ]]>";
    

    我一直试图自己写这个regex,但失败了。有人能帮我做这个吗?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Alex Paven    14 年前
    .

    • (?s) (?-s)

    ?<!

    • \"\<!\[CDATA\[
    • (.+)?
    • \]\]\>\";

    (
    {{
    (?<single>\w*)
    |
    (?<pair>
      (?<key>\w*)="\<!\[CDATA\[ (?<cdatavalue>.*)?\]\]\>";*)
    }}
    )+
    

    (
    {{
    (?<title>.*?)
    \|
    ((?<single>\w*)
    |
    (?<pair>
      (?<key>\w*)
      ="\<!\[CDATA\[
      (?<cdatavalue>.+)?
      \]\]\>";
    )+
    )
    }}
    )+
    

    • title
    • single pair string.IsNullOrEmpty
    • key cdatavalue

    {{asp:sample|test}}
    {{asp:codesample|Text="<![CDATA[this is text on the first line<br />
    this is text on the second line]]>";}}
    

    screenshot of results in Expresso

    Expresso

        2
  •  1
  •   Maate    14 年前

    Regex r = new Regex("{{(?<single>([a-z0-9:]*))\\|((?<pair>([a-z0-9:]*=\"[^\"]*\";))*)}}", RegexOptions.Singleline | RegexOptions.IgnoreCase);