unicode正则表达式;无效的xml字符

cu6pst1q  于 2021-07-03  发布在  Java
关注(0)|答案(6)|浏览(567)

有效xml字符的列表是众所周知的,正如规范所定义的:


# x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

我的问题是,通过使用unicode常规类别,是否可以为这个(或其逆)生成pcre正则表达式,而不必对代码点进行硬编码。反转可能类似于[\p{cc}\p{cs}\p{cn}],只是不正确地覆盖换行符和制表符,并且遗漏了一些其他无效字符。

6bc51xsx

6bc51xsx1#

我知道这不完全是对你问题的回答,但把它放在这里很有帮助:
匹配有效xml字符的正则表达式:

[\u0009\u000a\u000d\u0020-\uD7FF\uE000-\uFFFD]

因此,要从xml中删除无效字符,可以执行以下操作

// filters control characters but allows only properly-formed surrogate sequences
private static Regex _invalidXMLChars = new Regex(
    @"(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFEFF\uFFFE\uFFFF]",
    RegexOptions.Compiled);

/// <summary>
/// removes any unusual unicode characters that can't be encoded into XML
/// </summary>
public static string RemoveInvalidXMLChars(string text)
{
    if (string.IsNullOrEmpty(text)) return "";
    return _invalidXMLChars.Replace(text, "");
}

我有一个常驻的regex/xml天才,他对4400多个帖子投了赞成票,检查一下,他就签了。

v7pvogib

v7pvogib2#

如果xml中存在十六进制代码,上述解决方案对我来说就不起作用。例如 <element>&#x8;</element> 以下代码将中断:

string xmlFormat = "<element>{0}</element>";
string invalid = " &#x8;";
string xml = string.Format(xmlFormat, invalid);
xml = Regex.Replace(xml, @"[\x01-\x08\x0B\x0C\x0E\x0F\u0000-\u0008\u000B\u000C\u000E-\u001F]", "");
XDocument.Parse(xml);

它返回:
xmlexception:“”(十六进制值0x08)是无效字符。第1行,位置14。
以下是改进的regex并修复了上述问题:
&#x([0-8bcef]| 1[0-9a-fa-f])|[\x01-\x08\x0b\x0c\x0e\x0f\u0000-\u0008\u000b\u000c\u000e-\u001f]
以下是前300个unicode字符的单元测试,并验证是否只删除无效字符:

[Fact]
        public void validate_that_RemoveInvalidData_only_remove_all_invalid_data()
        {
            string xmlFormat = "<element>{0}</element>";
            string[] allAscii = (Enumerable.Range('\x1', 300).Select(x => ((char)x).ToString()).ToArray());
            string[] allAsciiInHexCode = (Enumerable.Range('\x1', 300).Select(x => "&#x" + (x).ToString("X") + ";").ToArray());
            string[] allAsciiInHexCodeLoweCase = (Enumerable.Range('\x1', 300).Select(x => "&#x" + (x).ToString("x") + ";").ToArray());

            bool hasParserError = false;
            IXmlSanitizer sanitizer = new XmlSanitizer();

            foreach (var test in allAscii.Concat(allAsciiInHexCode).Concat(allAsciiInHexCodeLoweCase))
            {
                bool shouldBeRemoved = false;
                string xml = string.Format(xmlFormat, test);
                try
                {
                    XDocument.Parse(xml);
                    shouldBeRemoved = false;
                }
                catch (Exception e)
                {
                    if (test != "<" && test != "&") //these char are taken care of automatically by my convertor so don't need to test. You might need to add these.
                    {
                        shouldBeRemoved = true;
                    }
                }
                int xmlCurrentLength = xml.Length;
                int xmlLengthAfterSanitize = Regex.Replace(xml, @"&#x([0-8BCEF]|1[0-9A-F]);|[\u0000-\u0008\u000B\u000C\u000E-\u001F]", "").Length;
                if ((shouldBeRemoved && xmlCurrentLength == xmlLengthAfterSanitize) //it wasn't properly Removed
                    ||(!shouldBeRemoved && xmlCurrentLength != xmlLengthAfterSanitize)) //it was removed but shouldn't have been
                {
                    hasParserError = true;
                    Console.WriteLine(test + xml);
                }
            }
            Assert.Equal(false, hasParserError);
        }
tzcvj98z

tzcvj98z3#

对于在utf-16中内部存储代码点的系统,通常对0xffff以上的代码点使用代理项对(xd800 xdfff),在这些系统中,必须验证是否确实可以使用例如\u12345或必须将其指定为代理项对(我刚刚发现在c语言中可以使用\u1234(16位)和\u00001234(32位))
根据微软的说法,“w3c建议不允许在元素或属性名中使用代理字符。”在搜索w3s网站时,我发现c079和c078可能是我感兴趣的。

bttbmeg0

bttbmeg04#

我在java中尝试了这个方法,效果很好:

private String filterContent(String content) {
    return content.replaceAll("[^\\u0009\\u000a\\u000d\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");
}

谢谢你,杰夫。

piv4azn7

piv4azn75#

在php中,正则表达式如下所示:

protected function isStringValid($string)
{
    $regex = '/[^\x{9}\x{a}\x{d}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u';

    return (preg_match($regex, $string, $matches) === 0);
}

这将处理xml规范的所有3个范围:


# x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
q5iwbnjs

q5iwbnjs6#

使用xmlconvert.isxmlchar方法(从.net framework 4.0开始提供)删除c中不正确xml字符的另一种方法

public static string RemoveInvalidXmlChars(string content)
{
   return new string(content.Where(ch => System.Xml.XmlConvert.IsXmlChar(ch)).ToArray());
}

或者您可以检查所有字符是否都是xml有效的。

public static bool CheckValidXmlChars(string content)
{
   return content.All(ch => System.Xml.XmlConvert.IsXmlChar(ch));
}

.net小提琴-https://dotnetfiddle.net/v1tnus
例如,垂直制表符(\v)对xml无效,它是有效的utf-8,但不是有效的xml 1.0,甚至许多库(包括libxml2)都没有找到它并默默地输出无效的xml。

相关问题