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)

(我使用反向引用来简化正则表达式,但它们不是必需的)

请注意,当它匹配时,它只会匹配字符串的开头,它不会匹配你的无效声明。如果您确实需要非空匹配,则可以在前瞻后添加 (&lt;[^&gt;]*&gt;)

【讨论】:

【参考方案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 声明 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C#Regex使用匹配值替换

XM概述

phpstorm 搜索

PowerShell Lookbehind 的 RegeX 代码在 IP 寻址上不匹配

在 RegEx 匹配中使用双 bang (!!) 是不是安全? [复制]

RegEx - 匹配以冒号开头的子字符串