9

我需要一个正则表达式来查找所有不是 xml-tags 的 '<' 或 '>'。

例子:

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

应该找到

<><<>

例子:

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

应该找到

<<>

所以,任何“<”或“>”不在标签中的命中(是的,我们也有应该考虑到的自动关闭标签:)

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

编辑#3:

所以我想要做的是从包含带有一些附加标签(很少有已知标签)的 HTML 的文本中获取标签中不包含的所有 '<' 和 '>' 。

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

<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>

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

4

7 回答 7

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 和 '&' 文本,仅用于测试。

于 2013-06-11T22:54:52.147 回答
3

使用This question中的一种方法并删除输入的html标签

然后

string output = new string(input.ToCharArray().Where(c=> c=='<'||c=='>').ToArray());
于 2013-06-09T17:34:46.097 回答
2

从您的示例来看,您似乎不是在搜索主题所建议的 XML 文件,而是在搜索类似 XML 的文件 - 如果它们不包含您正在寻找的“<”和“>”字符,那么它们可能是 XML 文件.

但是您没有足够清楚地指定任务。应该发生什么,例如,

<tag1>xxxx</tag2>

或与

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

仅使用正则表达式很难(也许不可能)实现第二种情况。您需要定义要接受的语法或输入语言(XML 的扩展)并使用递归解析技术对其进行解析。

于 2013-06-09T21:07:43.877 回答
0

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

MatchCollection matches = Regex.Matches(YourHTML, @"(?<=<.*?>).+(?=<.*?>)");
foreach (Match match in matches)
{
    YourHTML = YourHTML.Replace(match.Value, HttpUtility.HtmlEncode(match.Value));
}
于 2013-06-11T20:26:48.607 回答
0

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

  1. 从左到右搜索打开的标签,即<something>.
  2. 如果找到,则在剩余的字符串中搜索匹配的关闭标签,</something>
  3. 只要您能找到匹配对,就对刚刚找到的打开和关闭标签之间的字符串递归地重复步骤一和二
  4. 对于没有找到打开/关闭标记对的字符串序列,将所有出现的<and>替换为转义符。
于 2013-06-11T18:56:46.237 回答
0

鉴于编辑#3中问题的新表述,我认为您可以使用匹配“<”的正则表达式来解决它,然后是否定的前瞻

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

如果后面没有已知标记名之一,则匹配<,然后将其替换"<""&lt;"

于 2013-06-12T08:33:22.647 回答
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", "");
    }
于 2013-06-18T08:55:15.157 回答