使用正则表达式删除XML标签及其内容
我有以下字符串,我想删除<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, "&", "&") str = Replace(str, "'", "'") str = Replace(str, """", """) 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, ">", ">")
结束功能
朋友函数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类是否是最好的解决方案。