有效xml字符的列表是众所周知的,正如规范所定义的:
# x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
我的问题是,通过使用unicode常规类别,是否可以为这个(或其逆)生成pcre正则表达式,而不必对代码点进行硬编码。反转可能类似于[\p{cc}\p{cs}\p{cn}],只是不正确地覆盖换行符和制表符,并且遗漏了一些其他无效字符。
6bc51xsx1#
我知道这不完全是对你问题的回答,但把它放在这里很有帮助:匹配有效xml字符的正则表达式:
[\u0009\u000a\u000d\u0020-\uD7FF\uE000-\uFFFD]
因此,要从xml中删除无效字符,可以执行以下操作
// filters control characters but allows only properly-formed surrogate sequencesprivate 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, "");}
// 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多个帖子投了赞成票,检查一下,他就签了。
v7pvogib2#
如果xml中存在十六进制代码,上述解决方案对我来说就不起作用。例如 <element></element> 以下代码将中断:
<element></element>
string xmlFormat = "<element>{0}</element>";string invalid = " ";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);
string xmlFormat = "<element>{0}</element>";
string invalid = " ";
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); }
[Fact]
public void validate_that_RemoveInvalidData_only_remove_all_invalid_data()
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
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);
tzcvj98z3#
对于在utf-16中内部存储代码点的系统,通常对0xffff以上的代码点使用代理项对(xd800 xdfff),在这些系统中,必须验证是否确实可以使用例如\u12345或必须将其指定为代理项对(我刚刚发现在c语言中可以使用\u1234(16位)和\u00001234(32位))根据微软的说法,“w3c建议不允许在元素或属性名中使用代理字符。”在搜索w3s网站时,我发现c079和c078可能是我感兴趣的。
bttbmeg04#
我在java中尝试了这个方法,效果很好:
private String filterContent(String content) { return content.replaceAll("[^\\u0009\\u000a\\u000d\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");}
private String filterContent(String content) {
return content.replaceAll("[^\\u0009\\u000a\\u000d\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");
谢谢你,杰夫。
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);}
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个范围:
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());}
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));}
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。
6条答案
按热度按时间6bc51xsx1#
我知道这不完全是对你问题的回答,但把它放在这里很有帮助:
匹配有效xml字符的正则表达式:
因此,要从xml中删除无效字符,可以执行以下操作
我有一个常驻的regex/xml天才,他对4400多个帖子投了赞成票,检查一下,他就签了。
v7pvogib2#
如果xml中存在十六进制代码,上述解决方案对我来说就不起作用。例如
<element></element>
以下代码将中断:它返回:
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字符的单元测试,并验证是否只删除无效字符:
tzcvj98z3#
对于在utf-16中内部存储代码点的系统,通常对0xffff以上的代码点使用代理项对(xd800 xdfff),在这些系统中,必须验证是否确实可以使用例如\u12345或必须将其指定为代理项对(我刚刚发现在c语言中可以使用\u1234(16位)和\u00001234(32位))
根据微软的说法,“w3c建议不允许在元素或属性名中使用代理字符。”在搜索w3s网站时,我发现c079和c078可能是我感兴趣的。
bttbmeg04#
我在java中尝试了这个方法,效果很好:
谢谢你,杰夫。
piv4azn75#
在php中,正则表达式如下所示:
这将处理xml规范的所有3个范围:
q5iwbnjs6#
使用xmlconvert.isxmlchar方法(从.net framework 4.0开始提供)删除c中不正确xml字符的另一种方法
或者您可以检查所有字符是否都是xml有效的。
.net小提琴-https://dotnetfiddle.net/v1tnus
例如,垂直制表符(\v)对xml无效,它是有效的utf-8,但不是有效的xml 1.0,甚至许多库(包括libxml2)都没有找到它并默默地输出无效的xml。