RegEx - 当版本号不是“1.0”时匹配 XML 声明 [关闭]
Posted
技术标签:
【中文标题】RegEx - 当版本号不是“1.0”时匹配 XML 声明 [关闭]【英文标题】:RegEx - Match on XML declarations when the version # is not "1.0" [closed] 【发布时间】:2017-09-10 22:20:04 【问题描述】:我想为此使用 RegEx。
我需要找到错误的 XML 声明和任何不是 1.0 版的东西
以下是有效匹配项:错误声明
<? xml ver="1.0" encoding="UTF-8"?>
错误的声明
<?xml version="1.0' encoding=UTF-8>
错误的声明
<?xml ?>
错误的声明(不在第一行开始)
.....
<? xml ver="1.0" encoding="UTF-8"?>
1.1 版(单引号)
<?xml version='1.1' encoding='UTF-8'?>
1.1 版(双引号)
<?xml version="1.1" encoding="UTF-8"?>
版本错误#
<?xml version='999999' encoding='UTF-8'?>
1.1 版(多行) - 不确定是否允许使用多行格式,但我已经看到它完成了,我需要检查一下。
<?xml version="1.1" encoding="UTF-8" standalone="no" ?>
我们只希望匹配 invalid XML 声明 OR 具有 1.0 以外版本的 XML 声明
以下为有效的 XML 1.0 声明。这些永远不应该返回匹配项:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <?xml version= "1.0" encoding= 'UTF-8' standalone= "no" ?> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
【问题讨论】:
由于正则表达式尚未完全标准化,所有带有此标签的问题还应包含一个标签,指定适用的编程语言或工具。 — 您使用的是哪种语言或工具? 好收获!谢谢!我添加了一个 C# 标签。 是的,任何允许空格的地方都允许换行。此外,在您的示例中没有空格的地方允许使用空格,例如“=”符号周围。standalone
和 new-line-as-space 在 XML 1.0 中都有效。为什么他们被排除在外?
@kennytm 如果我错过了一个可能的例子,我深表歉意。这不是故意的。
【参考方案1】:
XML 1.0 的 XML declaration grammar 是:
XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
Eq ::= S? '=' S?
VersionNum ::= '1.0'
EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
S ::= (#x20 | #x9 | #xD | #xA)+
这可以简单地转换为 C# 的正则表达式表示法,我们可以编写 匹配有效声明的正则表达式:
new Regex(@"
\A<\?xml
[ \t\n\r]+version[ \t\n\r]*=[ \t\n\r]*([""'])1\.0\1
(?:[ \t\n\r]+encoding[ \t\n\r]*=[ \t\n\r]*([""'])[A-Za-z][A-Za-z0-9._-]*\2)?
(?:[ \t\n\r]+standalone[ \t\n\r]*=[ \t\n\r]*([""'])(?:yes|no)\3)?
[ \t\n\r]*
\?>
", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace)
这可以使用否定的前瞻来反转,以使其在缺少有效声明时匹配。
new Regex(@"
\A(?!<\?xml
[ \t\n\r]+version[ \t\n\r]*=[ \t\n\r]*([""'])1\.0\1
(?:[ \t\n\r]+encoding[ \t\n\r]*=[ \t\n\r]*([""'])[A-Za-z][A-Za-z0-9._-]*\2)?
(?:[ \t\n\r]+standalone[ \t\n\r]*=[ \t\n\r]*([""'])(?:yes|no)\3)?
[ \t\n\r]*
\?>)
", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace)
(我使用反向引用来简化正则表达式,但它们不是必需的)
请注意,当它匹配时,它只会匹配字符串的开头,它不会匹配你的无效声明。如果您确实需要非空匹配,则可以在前瞻后添加 (<[^>]*>)
。
【讨论】:
【参考方案2】:这是我的正则表达式版本,满足您的条件:
(<\?xml\s+version="1\.0"\s+encoding="[^"]+"\s+standalone="((yes)|(no))"\s*\?>)
要查看example 并调试您的表达式,我推荐在线regex101 测试仪。
这是我的 C# 函数示例,如果文件内容以您的观点声明的权利开头,则返回 true
:
private bool ValidateDeclaration(string fileContent)
var re = Regex.Match(fileContent, @"(<\?xml\s+version=""1\.0""\s+encoding=""[^""]+""\s+standalone=""((yes)|(no))""\s*\?>)");
return re.Success && re.Groups[1].Index == 0;
更新(在您编辑问题后):
有无数个错误的表达式,所以并不对应所有的,除了对应的部分,只是重命名函数和否定结果=)。如果你想允许空间,只需在他们可以站立的任何地方添加[ ]*
private bool IsInvalidDeclaration(string fileContent)
var re = Regex.Match(fileContent, @"(<\?xml\s+version=""1\.0""\s+encoding=""[^""]+""\s+standalone=""((yes)|(no))""\s*\?>)");
return !(re.Success && re.Groups[1].Index == 0);
【讨论】:
【参考方案3】:我通常只是跳过阅读标识行:
StreamReader reader = new StreamReader(FILENAME);
reader.ReadLine();
XDocument doc = XDocument.Load(reader);
【讨论】:
这是非常糟糕的做法。不需要 XML 声明后跟换行符,而在机器生成的 XML 中通常不需要。 这是网络库不处理所有标识选项的唯一解决方法。 如果您真的必须去掉 XML 声明,那么寻找永远存在的“?>”肯定比不存在的换行符要好。你不应该在删除之前检查 XML 声明是否存在吗? 我的代码非常简单,99% 的时间都可以工作。为什么要添加不必要的并发症。搜索 ?> 将需要阅读更多的文件并且使用没有多大意义的巨大 xml。我的解决方案可以很好地与 XmlReader 以及 XDocument 一起使用。 我从未在可以接受 99% 可靠性的环境中工作过。以上是关于RegEx - 当版本号不是“1.0”时匹配 XML 声明 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
PowerShell Lookbehind 的 RegeX 代码在 IP 寻址上不匹配