找到所有“多于或少于”字符,这些字符不是xml中的标签

时间:2013-06-09 17:23:30

标签: c# xml regex

我需要一个正则表达式才能找到所有'<'或'>'这不是xml标签。

示例:

<tag1>W<E><E</tag1>Z<>S

应该找到

<><<>

示例:

<tag1>W<E><E</E></tag1>Z<>S

应该找到

<<>

所以,任何点击'&lt;'或'&gt;'不是标签(是的,我们也有自我关闭标签,应该考虑到这一点)。

编辑#2: 我最终想做的是用html编码的值替换所有匹配。

编辑#3:

所以我想做的是从一个包含HTML的文本和一些额外的标签(很少有已知的标签)得到所有'&lt;'和'&gt;'这不包含在标签中。

示例(我想找到的粗体,所以我可以用它们的编码值替换它们):

<div>
  <a href="link">Link with < characters</a>
  <knownTag>Text with character ></knownTag>
  <knownTag>Text < again ></knownTag>
<div>

结果应该是:

<div>
  <a href="link">Link with &lt; characters</a>
  <knownTag>Text with character &gt;</knownTag>
  <knownTag>Text &lt; again &gt;</knownTag>
<div>

关于如何解决这个问题的任何想法?

7 个答案:

答案 0 :(得分:6)

这可以用正则表达式来完成;但是,它并不像你建议的那么简单。您需要找到有效的标签并对其进行处理才能使其正常工作。我刚刚在编写一个快速且轻巧的xml / html解析器时就这样做了。该代码可在以下网址获得:

http://csharptest.net/browse/src/Library/Html/XmlLightParser.cs http://csharptest.net/browse/src/Library/Html/XmlLightInterfaces.cs

要使用解析器,您将从两个源文件的后面实现已定义的接口IXmlLightReader。以下示例生成您想要的结果,并且还处理您未提及的其他几个功能,如CDATA部分,处理指令,DTD等。

class RegexForBadXml
{
    const string Input = "<?xml version=\"1.0\"?>\r\n<div>\r\n\t<a href=\"link\">Link with < characters</a>\r\n\t<knownTag>Text with character > &and other &#BAD; stuff</knownTag>\r\n\t<knownTag>Text < again ></knownTag>\r\n\t<knownTag><![CDATA[ Text < again > ]]></knownTag>\r\n<div>";

    private static void Main()
    {
        var output = new StringWriter();
        XmlLightParser.Parse(Input, XmlLightParser.AttributeFormat.Html, new OutputFormatter(output));
        Console.WriteLine(output.ToString());
    }

    private class OutputFormatter : IXmlLightReader
    {
        private readonly TextWriter _output;
        public OutputFormatter(TextWriter output)
        {
            _output = output;
        }

        void IXmlLightReader.StartDocument() { }
        void IXmlLightReader.EndDocument() { }

        public void StartTag(XmlTagInfo tag)
        {
            _output.Write(tag.UnparsedTag);
        }

        public void EndTag(XmlTagInfo tag)
        {
            _output.Write(tag.UnparsedTag);
        }

        public void AddText(string content)
        {
            _output.Write(HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(content)));
        }

        public void AddComment(string comment)
        {
            _output.Write(comment);
        }

        public void AddCData(string cdata)
        {
            _output.Write(cdata);
        }

        public void AddControl(string cdata)
        {
            _output.Write(cdata);
        }

        public void AddInstruction(string instruction)
        {
            _output.Write(instruction);
        }
    }
}

前面的程序输出以下结果:

<?xml version="1.0"?>
<div>
    <a href="link">Link with &lt; characters</a>
    <knownTag>Text with character &gt; &amp;and other &amp;BAD; stuff</knownTag>
    <knownTag>Text &lt; again &gt;</knownTag>
    <knownTag><![CDATA[ Text < again > ]]></knownTag>
<div>

注意:我添加了xml声明,CDATA和'&amp;'仅供测试的文字。

答案 1 :(得分:3)

使用This question中的方法之一并删除输入的

然后

string output = new string(input.ToCharArray().Where(c=> c=='<'||c=='>').ToArray());

答案 2 :(得分:2)

从您的示例来看,似乎您不是像主题建议的那样搜索XML文件,而是类似XML的文件 - 如果它们不包含“&lt;”,则可能是XML文件。和“&gt;”你正在寻找的人物。

但是你还没有明确指出任务。应该怎么做,例如,

<tag1>xxxx</tag2>

<tag1><x a="</tag1>"/></tag1>

单独使用正则表达式来完成第二种情况非常困难(也许是不可能的)。您需要定义要接受的语法或输入语言(XML的扩展)并使用递归解析技术对其进行解析。

答案 3 :(得分:0)

在您的有限情况下,似乎有一种可能有效的算法策略,可以概述如下:

  1. 从左到右搜索开放标记,即<something>
  2. 如果找到,请在剩余字符串中搜索匹配的关闭标记</something>
  3. 只要找到匹配的对,就可以递归重复第一步和第二步,找到刚刚找到的打开和关闭标记之间的字符串
  4. 对于未找到打开/关闭标记对的字符串序列, 用转义替换所有出现的<>

答案 4 :(得分:0)

我对您的问题并不太了解,但我编写了一个代码,该代码采用您的HTML示例并返回与您预期的HTML结果相同的HTML结果。

MatchCollection matches = Regex.Matches(YourHTML, @"(?<=<.*?>).+(?=<.*?>)");
foreach (Match match in matches)
{
    YourHTML = YourHTML.Replace(match.Value, HttpUtility.HtmlEncode(match.Value));
}

答案 5 :(得分:0)

鉴于编辑#3中你的问题的新表述,我认为你可以使用匹配“&lt;”的正则表达式解决它接下来是负向前瞻

<(?!(/?(a|b|div|p|....|!--|!\[CDATA\[))

匹配<(如果之后没有其中一个已知的标记名称),然后将此"<"替换为"&lt;"

答案 6 :(得分:0)

    static string test(string input)
    {
        var r = @"(<(.*?)>)(.*?)</\2>";
        while (Regex.IsMatch(input, r))
            input = Regex.Replace(input, r, "$3");
        return Regex.Replace(input, @"\w", "");
    }