【问题标题】:Replace text not contained in a tag using either Regex or XmlParser使用 Regex 或 XmlParser 替换标签中未包含的文本
【发布时间】:2011-05-17 19:58:09
【问题描述】:

我知道使用正则表达式来解析或操作 HTML/XML 是一个坏主意,而且我通常不会这样做。但考虑它是因为缺乏替代品。

我需要使用 C# 替换尚未成为标记(理想情况下是具有特定 id 的跨度标记)一部分的字符串中的文本。

例如,假设我想将以下文本中不在跨度内的所有 ABC 实例替换为替代文本(在我的情况下是另一个跨度)

ABC at start of line or ABC here must be replaced but, <span id="__publishingReusableFragment" >ABC inside span must not be replaced with anything. Another ABC here </span> this ABC must also be replaced

我尝试将正则表达式与前瞻和后瞻断言一起使用。沿线的各种组合

string regexPattern = "(?<!id=\"__publishingReusableFragment\").*?" + stringToMatch + ".*?(?!span)";

但放弃了。

我尝试将其加载到 XElement 中,并尝试从那里创建编写器并获取不在节点内的文本。但也想不通。

XElement xel = XElement.Parse("<payload>" + inputString + @"</payload>");
XmlWriter requiredWriter = xel.CreateWriter();

我希望以某种方式使用编写器来获取不属于节点的字符串并替换它们。

基本上,我愿意接受任何解决此问题的建议/解决方案。

提前感谢您的帮助。

【问题讨论】:

    标签: c# regex html-parsing xml-parsing regex-negation


    【解决方案1】:
    resultString = Regex.Replace(subjectString, 
        @"(?<!              # assert that we can't match the following 
                            # before the current position: 
                            # An opening span tag with specified id
         <\s*span\s*id=""__publishingReusableFragment""\s*>
         (?:                # if it is not followed by...
          (?!<\s*/\s*span)  # a closing span tag
          .                 # at any position between the opening tag
         )*                 # and our text
        )                   # End of lookbehind assertion
        ABC                 # Match ABC", 
        "XYZ", RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
    

    适用于所有关于 HTML 解析的警告(您似乎知道,所以我不会在这里重复它们)仍然有效。

    如果正则表达式前面没有&lt;span id=__publishingReusableFragment"&gt; 开头标记并且两者之间没有关闭&lt;span&gt; 标记,则该正则表达式匹配ABC。如果可以嵌套&lt;span&gt; 标签,它显然会失败。

    【讨论】:

    • 看起来不错。但是如果 span 标签中有一些额外的属性,例如: ... ... 我尝试将正则表达式的 span 部分替换为跟随 span.?id=""__publishingReusableFragment"".*?> 但现在它在 span 标签结束后不匹配 - ... 这个 ABC。 ..
    • 您开始遇到使用正则表达式解析 HTML 不是一个好主意的所有原因。如果您的属性从不包含&gt;,您可以使用&lt;\s*span[^&gt;]*id=""__publishingReusableFragment""[^&gt;]*&gt; 并希望获得最好的结果。
    • 是的,就是这样,谢谢。是的,这就是为什么我希望使用 LinqToXML 或一个好的 LinqToHtml 库来处理它可能是一个想法。这只是一个一次性的导入工具,需要在输入过程中处理一些数据以减少手动后期处理。
    【解决方案2】:

    我知道它有点难看,但这会起作用

    var s =
        @"ABC at start of line or ABC here must be replaced but, <span id=""__publishingReusableFragment"" >ABC inside span must not be replaced with anything. Another ABC here </span> this ABC must also be replaced";
    var newS = string.Join("</span>",s.Split(new[] {"</span>"}, StringSplitOptions.None)
        .Select(t =>
            {
                var bits = t.Split(new[] {"<span"}, StringSplitOptions.None);
                bits[0] = bits[0].Replace("ABC","DEF");
                return string.Join("<span", bits);
            }));
    

    【讨论】:

    • 一点也不丑。这是做需要做的事情的好方法(这有点难看)。唯一的问题是它忽略了所有跨度。不只是跨越一个特定的 id,比如正则表达式。不过,这可能已经扩展为适合我,并且在许多其他情况下会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多