我正在尝试创建一个C#正则表达式,它检测我们的.csproj文件中的引用何时没有< SpecificVersion>设置为False(必须在所有< s之后添加一个空格以使其在StackOverflow中正确显示)。所以这些是我需要处理的案例:
1. <Reference Include="IQ.MyStuff1, Version=4.1.0.0, Culture=neutral, processorArchitecture=MSIL" />
2. <Reference Include="IQ.MyStuff2, Version=4.7.22.21777, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\DebugDLLFiles\IQ.MyStuff2.dll</HintPath>
</Reference>
3. <Reference Include="IQ.MyStuff3, Version=4.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\DebugDLLFiles\IQ.MyStuff3.dll</HintPath>
<SpecificVersion>True</SpecificVersion>
</Reference>
4. <Reference Include="IQ.MyStuff4, Version=4.5.3.17401, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>True</SpecificVersion>
</Reference>
所以基本上任何没有明确具有“&lt; SpecificVersion&gt; False&lt; / SpecificVersion&gt;”的文件引用在它。
所以让我们忽略第一种情况,因为它没有像其他3那样的身体,可以区别对待。所以这就是我到目前为止所做的:
<Reference(\s|\n|\r)*? # Match against '<Reference '.
Include=""IQ\..*?"" # Match against the entire Include attribute; We only care about IQ DLLs.
(\s|\n\r)*?> # Eat any whitespace and match against the closing tag character.
[What should go here?]
</Reference> # Match against the closing tag.
所以我在[应该去哪里?]块中尝试了很多东西,但似乎无法让任何工作完全正常。我最接近的是使用以下块:
(?! # Do a negative look-ahead to NOT match against this Reference tag if it already has <SpecificVersion>False</SpecificVersion>.
(.|\n|\r)*? # Eat everything before the <SpecificVersion> tag, if it even exists.
<SpecificVersion>(\s|\n|\r)*?False(\s|\n|\r)*?</SpecificVersion> # Specify that we don't want to match if this tag already has <SpecificVersion>False</SpecificVersion>.
)
(.|\n|\r)*? # Eat everything after the <SpecificVersion> tag, if it even existed.
这适用于所有情况,除了在我想要匹配的任何一个下面有有效引用的地方,其中有效的引用看起来像:
<Reference Include=\"IQ.MyStuff5, Version=4.5.3.17401, Culture=neutral, processorArchitecture=MSIL\">
<SpecificVersion>False</SpecificVersion>
</Reference>
我正在使用的预测似乎不会停留在&lt; /参考和GT;标记,但继续向下看整个文件,以确保其下面的文字没有“&lt; SpecificVersion&gt; False&lt; / SpecificVersion&gt;”。
如何在第一个“&lt; / Reference&gt;”中使我的前瞻停止它会遇到,或者如果你有另一种方法来解决我的问题,我也会对此持开放态度。任何建议表示赞赏。感谢。
答案 0 :(得分:3)
放弃正则表达式。它注定要失败。不是XML吗?为什么不这样对待呢?
“don't parse HTML with regex”规则同样适用于XML。
答案 1 :(得分:2)
如果你想尝试使用正则表达式,我会建议这样的事情:
<Reference[^>]*?>(?:.(?!</Reference>))*?<SpecificVersion>([^<]*?)</SpecificVersion>
它匹配所有标签内的标签 - 即它将完全忽略任何没有标签的参考标签。
我在regexpal中在线测试它似乎在多种情况下正常工作。
编辑:
如果你想匹配完全不存在SpecificVersion标签的情况,请尝试进行此更改 - 它将尝试使用标签匹配选项,但如果失败,它仍将匹配
<Reference[^>]*?>(?:.(?!</Reference>))*?(<SpecificVersion>([^<]*?)</SpecificVersion>)|<Reference[^>]*?>(?:.(?!</Reference>))*?(?:<SpecificVersion>([^<]*?)</SpecificVersion>)?
让我知道你是如何上场的。
答案 2 :(得分:0)
因此,根据花花公子的建议,我研究了正则表达式的替代品。我发现了Linq To XML,它很容易解决我的问题。这是我用来解决问题的代码。它查找.csproj文件中的所有引用到IQ DLL文件,并确保它们都具有&lt; SpecificVersion&GT;假&LT; / SpecificVersion&GT;元件。仅仅为了一些背景信息,我需要这样做的原因是当特定版本设置为True时,我们的构建在我们的本地机器上运行良好,但它在我们的TFS构建服务器上中断,除非它被设置为False。我很确定这样做的原因是我们的TFS构建更新了版本号,因此每个项目设置使用的版本都是过时的。无论如何,这是代码:)
// Let's parse us some XML!
XElement xmlFile = XElement.Load(filePath);
// Grab all of the references to DLL files.
var iqReferences = xmlFile.Descendants().Where(e => e.Name.LocalName.Equals("Reference", StringComparison.InvariantCultureIgnoreCase));
// We only care about iQ DLL files.
iqReferences = iqReferences.Where(r => r.Attribute("Include") != null && r.Attribute("Include").Value.StartsWith("IQ.", StringComparison.InvariantCultureIgnoreCase));
// If this project file doesn't reference any iQ DLL files, move on to the next project file.
if (!iqReferences.Any())
continue;
// Make sure they all have <SpecificVersion> set to False.
foreach (XElement reference in iqReferences)
{
// If this Reference element already has a child SpecificVersion element whose value is false, skip this reference since it is good.
if (reference.Elements().Where(e => e.Name.LocalName.Equals("SpecificVersion", StringComparison.InvariantCultureIgnoreCase))
.Any(e => e.Value.Equals("False", StringComparison.InvariantCultureIgnoreCase)))
continue;
// Add this reference to the list of bad references.
badReferences.AppendLine("\t" + reference.Attribute("Include").Value);
// Fix the reference.
reference.SetElementValue(reference.Name.Namespace + "SpecificVersion", "False");
}