用于删除 XML 标记及其内容的正则表达式

Posted

技术标签:

【中文标题】用于删除 XML 标记及其内容的正则表达式【英文标题】:Regular expression to remove XML tags and their content 【发布时间】:2010-09-12 09:47:33 【问题描述】:

我有以下字符串,我想删除 <bpt *>*</bpt><ept *>*</ept>(注意其中的附加标记内容也需要删除)而不使用 XML 解析器(对于小字符串来说开销太大)。

The big <bpt i="1" x="1" type="bold"><b></bpt>black<ept i="1"></b></ept> <bpt i="2" x="2" type="ulined"><u></bpt>cat<ept i="2"></u></ept> sleeps.

VB.NET 或 C# 中的任何正则表达式都可以。

【问题讨论】:

过滤器是什么意思?提炼?消除?请澄清。 避免使用 XML 解析器的原因是什么? 小字符串需要过滤,所以 XML Parser 开销是不可接受的。在这种情况下,过滤器被删除。 可以嵌套在 中吗?或相反亦然?如果是这样,问题就会复杂化。 如果存在任意嵌套,则没有涉及正则表达式的通用解决方案,并且由于嵌套有限,您的正则表达式会变得非常庞大且非常丑陋。 【参考方案1】:

如果您只想从字符串中删除所有标签,请使用此 (C#):

try 
    yourstring = Regex.Replace(yourstring, "(<[be]pt[^>]+>.+?</[be]pt>)", "");
 catch (ArgumentException ex) 
    // Syntax error in the regular expression

编辑:

我决定在我的解决方案中添加一个更好的选项。如果有嵌入标签,前一个选项将不起作用。这个新的解决方案应该去除所有 标签,无论是否嵌入。此外,此解决方案使用对原始 [be] 匹配的反向引用,以便找到完全匹配的结束标记。此解决方案还创建了一个可重用的 Regex 对象以提高性能,因此每次迭代都不必重新编译 Regex:

bool FoundMatch = false;

try 
    Regex regex = new Regex(@"<([be])pt[^>]+>.+?</\1pt>");
    while(regex.IsMatch(yourstring) ) 
        yourstring = regex.Replace(yourstring, "");
    
 catch (ArgumentException ex) 
    // Syntax error in the regular expression

附加说明:

在 cmets 中,一位用户表示担心 '.'模式匹配器将是 CPU 密集型的。虽然在独立的贪婪“。”的情况下这是正确的,但使用非贪婪字符“?”导致正则表达式引擎只向前看,直到找到模式中下一个字符的第一个匹配项而不是贪婪的 '.'这需要引擎一直向前看到字符串的末尾。我使用RegexBuddy 作为正则表达式开发工具,它包含一个调试器,可以让您查看不同正则表达式模式的相对性能。如果需要,它还会自动对您的正则表达式进行 cmets,因此我决定在此处包含这些 cmets 以解释上面使用的正则表达式:

    // <([be])pt[^>]+>.+?</\1pt>
// 
// Match the character "<" literally «<»
// Match the regular expression below and capture its match into backreference number 1 «([be])»
//    Match a single character present in the list "be" «[be]»
// Match the characters "pt" literally «pt»
// Match any character that is not a ">" «[^>]+»
//    Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
// Match the character ">" literally «>»
// Match any single character that is not a line break character «.+?»
//    Between one and unlimited times, as few times as possible, expanding as needed (lazy) «+?»
// Match the characters "</" literally «</»
// Match the same text as most recently matched by backreference number 1 «\1»
// Match the characters "pt>" literally «pt>»

【讨论】:

不错,除了使用“。”这是相当密集的CPU,如果你处理一个大的xml文件,这很重要。你可以用“[^]”代替它,不是吗? 对不起,对于子标签,你不能。最好改用“[^ø]”。【参考方案2】:

我想你想完全删除标签?

(<bpt .*?>.*?</bpt>)|(<ept .*?>.*?</ept>)

那个?在 * 之后使其不贪婪,因此它会尝试匹配尽可能少的字符。

您会遇到的一个问题是嵌套标签。 stuff 不会看到第二个,因为第一个匹配。

【讨论】:

【参考方案3】:

为什么说开销太大?你量过吗?还是你猜的?

使用正则表达式而不是正确的解析器是一种捷径,当有人提出类似

之类的东西时,您可能会遇到这种情况

【讨论】:

好吧,当您拥有非格式良好的 XML 时,您唯一可以做的就是使用正则表达式或其他一些拐杖。问题中的标记不是 XML,它具有相交的层次结构。【参考方案4】:

.NET 正则表达式引擎是否支持负前瞻?如果是,那么您可以使用

(<([eb])pt[^>]+>((?!</\2pt>).)+</\2pt>)

如果您删除所有匹配项,这会使 大黑猫睡觉。 超出上述字符串。但是请记住,如果您嵌套了 bpt/ept 元素,它将不起作用。 您可能还想在某些地方添加 \s 以允许在关闭元素等中使用额外的空格。

【讨论】:

【参考方案5】:

如果您打算使用正则表达式来删除 XML 元素,最好确保您的输入 XML 不使用来自不同名称空间的元素,或者包含您不想修改其内容的 CDATA 部分。

正确(即既高效又正确)的方法是使用 XSLT。将除特定元素之外的所有内容复制到输出的 XSLT 转换是恒等转换的简单扩展。编译转换后,它将非常快速地执行。而且不会有任何隐藏的缺陷。

【讨论】:

【参考方案6】:

是否有任何可能的方法来获得 regex.pattern 的 xml 类型文本的全局解决方案? 这样我就可以摆脱替换功能,而外壳使用正则表达式。 麻烦的是分析 是否按顺序排列.. 还将保留字符替换为 ' & 等等。 这是代码 '处理特殊字符函数 Friend 函数 ReplaceSpecChars(ByVal str As String) As String Dim arrLessThan As New Collection Dim arrGreaterThan As New Collection If Not IsDBNull(str) Then

  str = CStr(str)
  If Len(str) > 0 Then
    str = Replace(str, "&", "&amp;")
    str = Replace(str, "'", "&apos;")
    str = Replace(str, """", "&quot;")
    arrLessThan = FindLocationOfChar("<", str)
    arrGreaterThan = FindLocationOfChar(">", str)
    str = ChangeGreaterLess(arrLessThan, arrGreaterThan, str)
    str = Replace(str, Chr(13), "chr(13)")
    str = Replace(str, Chr(10), "chr(10)")
  End If
  Return str
Else
  Return ""
End If

结束函数 Friend Function ChangeGreaterLess(ByVal lh As Collection, ByVal gr As Collection, ByVal str As String) As String For i As Integer = 0 To lh.Count 如果 CInt(lh.Item(i)) > CInt(gr.Item(i)) 那么 str = Replace(str, "

  Next


    str = Replace(str, ">", "&gt;")

结束函数 Friend 函数 FindLocationOfChar(ByVal chr As Char, ByVal str As String) 作为集合 暗淡 arr 作为新系列 For i As Integer = 1 To str.Length() - 1 如果 str.ToCharArray(i, 1) = chr 则 arr.Add(i) 万一 下一个 返回 arr 结束函数

在问题标记处遇到问题

这是一个带有不同标签的标准 xml,我想分析..

【讨论】:

【参考方案7】:

你测量过这个吗?我在使用 .NET 的正则表达式引擎时遇到了性能问题,但相比之下,使用 Xml 解析器解析了大约 40GB 的 xml 文件没有问题(您需要使用 XmlReader但是更大的字符串)。

请发布一个实际的代码示例并提及您的性能要求:如果性能很重要,我怀疑Regex 类是这里的最佳解决方案。

【讨论】:

以上是关于用于删除 XML 标记及其内容的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

Python正则表达式删除所有方括号及其内容

用于查找 HTML 标签及其内容的正则表达式的否定 - java

正则表达式 - 将 HTML 转换为有效的 XML 标记 [重复]

正则表达式删除所有空的 HTML 标记

用于在 HTML 标记中提取特定文本内容的正则表达式

正则表达式用于匹配 img 标记的开始和结束尖括号内的所有文本