使用正则表达式删除XML标签及其内容

时间:2020-03-06 14:36:16  来源:igfitidea点击:

我有以下字符串,我想删除<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中的任何正则表达式都可以。

解决方案

我想我们想完全删除标签吗?

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

这 ? *表示非贪婪之后,因此它将尝试匹配尽可能少的字符。

我们将遇到的一个问题是嵌套标签。东西看不到第二个,因为第一个匹配。

.NET正则表达式引擎是否支持否定先行?如果是,那么我们可以使用

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

这使大黑猫睡着了。如果删除所有匹配项,则不在上面的字符串中。但是请记住,如果嵌套了bpt/ept元素,则它将不起作用。
我们可能还希望在某些位置添加\ s,以在结束元素等中留出额外的空格。

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

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

编辑:

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

bool FoundMatch = false;

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

添加条款:

用户在评论中表示担心"。"模式匹配器将占用大量CPU。对于独立的贪婪'。'情况确实如此,但使用非贪婪字符'?'导致正则表达式引擎仅向前查找,直到找到模式中下一个字符与贪婪的'的第一个匹配项为止。这要求引擎一直向前看直到字符串的末尾。我将RegexBuddy用作正则表达式开发工具,它包含调试器,可让我们查看不同正则表达式模式的相对性能。如果需要,它还会自动注释正则表达式,因此我决定在此处包括这些注释,以解释上面使用的正则表达式:

// <([be])pt[^>]+>.+?</pt>
// 
// 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 ??
// Match the characters "pt>" literally ?pt>?

为什么说开销太大?你测量了吗?还是在猜?

使用正则表达式而不是适当的解析器是一种快捷方式,当有人遇到类似<bpt foo =" bar>">

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

正确的方法(即性能和正确的方法)是使用XSLT。将除特定元素之外的所有内容复制到输出的XSLT转换是Identity转换的重要扩展。一旦转换被编译,它将执行得非常快。而且它不会包含任何隐藏的缺陷。

有什么可能的方法来获取regex.pattern的xml类型文本的全局解决方案?
这样,我将摆脱替换功能,而外壳使用正则表达式。
问题在于分析<>是否按顺序排列。
也将保留的字符替换为'&等等。
这是代码
'处理特殊字符功能
朋友函数ReplaceSpecChars(ByVal str As String)As String
Dim arrLessThan As New Collection
Dim arrGreaterThan As New Collection
如果不是IsDBNull(str),则

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

结束功能
朋友函数ChangeGreaterLess(ByVal lh作为集合,ByVal gr作为集合,ByVal str作为字符串)作为字符串
对于i As Integer = 0到lh.Count
如果CInt(lh.Item(i))> CInt(gr.Item(i))然后
str = Replace(str," <"," <")/////////问题/////
万一

Next

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

结束功能
朋友函数FindLocationOfChar(ByVal chr as Char,ByVal str As String)As Collection
Dim arr作为新收藏
对于i As Integer = 1到str.Length()1
如果str.ToCharArray(i,1)= chr然后
arr.Add(i)
万一
下一个
返回arr
结束功能

在问题标记处遇到麻烦

这是一个标准的xml,我要分析不同的标签。

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

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