【问题标题】:Cannot get regular expression work correctly with multiline无法使正则表达式与多行一起正常工作
【发布时间】:2010-09-22 07:29:12
【问题描述】:

我的应用程序有一个相当大的 XML 输出。我需要用我的程序对其进行处理,然后将其反馈给原始程序。这个 XML 中有一些需要填写我们替换的部分。有趣的部分是这样的:

<sys:customtag sys:sid="1" sys:type="Processtart" />
    <sys:tag>value</sys:tag>
    here are some other tags
    <sys:tag>value</sys.tag>
<sys:customtag sys:sid="1" sys:type="Procesend" />

并且该文档包含几个这样的部分。

我需要获取这些标签中的所有 XML 片段才能对其进行修改。我写了一个正则表达式来获取这些片段,但它不起作用:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(@"output.xml");
Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);
MatchCollection matches = regExp.Matches(xmlDoc.InnerXml);

如果我将所有内容放在一行中并在没有多行选项的情况下调用此正则表达式,它确实会找到每一个出现的地方。通过保持文件原样并设置多行选项,它不起作用。有什么问题,我应该改变什么?或者有没有更简单的方法可以在没有正则表达式的情况下获取这些标签之间的 XML 部分?

【问题讨论】:

    标签: c# regex multiline


    【解决方案1】:

    我相信使用的选项是 RegexOptions.Singleline 而不是 RegexOptions.Multiline (src)。允许 (.) 匹配换行符应该适用于您的情况。

    ...点也匹配换行符的模式称为“单行模式”。这有点不幸,因为这个术语很容易与“多线模式”混淆。多行模式只影响锚点,单行模式只影响点...当使用.NET框架的正则表达式类时,通过指定RegexOptions.Singleline来激活该模式,例如在Regex.Match("string ", "正则表达式", RegexOptions.Singleline)。

    【讨论】:

    • 就是这样,谢谢。我的意思是多行 = 多行模式。
    【解决方案2】:

    正则表达式字符“。”从不匹配换行符,即使设置了 MultiLine 选项。 相反,您应该使用[\s\S] 或其他匹配任何内容的组合。

    MultiLine 选项仅修改 ^(行开头代替字符串开头)和 $(行尾代替字符串结尾)的行为

    顺便说一句:确实,正则表达式不是扫描 HTML 的正确方法...

    【讨论】:

      【解决方案3】:

      RegExp 对 xml 来说是一个糟糕的工具……你能不能把它加载到 XDocument / XmlDocument 中并使用 xpath?如果你明确了你想要做的修改,我希望我们可以填补空白......在这种情况下,命名空间可能是使它变得复杂的主要因素,所以我们只需要使用XmlNamespaceManager

      这是一个例子,当然,它比正则表达式更复杂 - 但是,我希望它能够更好地处理 xml 的细微差别:

          string xml = @"<foo xmlns:sys=""foobar""><bar/><bar><sys:customtag sys:sid=""1"" sys:type=""Processtart"" />
      <sys:tag>value</sys:tag>
      here are some other tags
      <sys:tag>value</sys:tag>
      <sys:customtag sys:sid=""1"" sys:type=""Procesend"" /></bar><bar/></foo>";
      
          XmlDocument doc = new XmlDocument();
          doc.LoadXml(xml);
          XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
          mgr.AddNamespace("sys", "foobar");
          var matches = doc.SelectNodes("//sys:customtag[@sys:type='Processtart']", mgr);
          foreach (XmlElement start in matches)
          {
              XmlElement end = (XmlElement) start.SelectSingleNode("following-sibling::sys:customtag[@sys:type='Procesend'][1]",mgr);
              XmlNode node = start.NextSibling;
              while (node != null && node != end)
              {
                  Console.WriteLine(node.OuterXml);
      
                  node = node.NextSibling;
              }
          }
      

      【讨论】:

      • 我已经查看了 XPath 选项,但我没有找到任何可以将 XML 内容返回到标签之间的东西,这些标签与 XML 无关(我的意思是它们不是开始-关闭从 XML 的角度来看彼此的标签)。也许你有一个想法?
      • 嗯,xml 旨在用作树...一个简单的选择是只使用 ... - 但我快看一下……
      • 是的,我可以处理,但不幸的是,XML 来自一个我无法更改的应用程序,我必须以这种格式将它返回给同一个应用程序。我无法更改里面的 XML 标签。
      • 我会更新一个例子,但我个人可能想先用 xslt 重新格式化 xml...
      • 这也是一个不错的解决方案,谢谢。我目前正在使用正则表达式,但我会考虑您使用我的程序进行第二轮。
      【解决方案4】:

      如果您对此仍有疑问,可能是因为您在 RegexOptions 中使用 AND 而不是 OR。

      此代码错误,将零作为第二个参数传递给构造函数:

      Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
      RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);
      

      这段代码是正确的(就使用多个 RegexOptions 标志而言):

      Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
      RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-25
        • 2016-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多