0

我正在尝试创建一个 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>

所以基本上任何没有明确包含“<SpecificVersion>False</SpecificVersion>”的文件引用。

所以让我们忽略第一种情况,因为它没有像其他 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.

所以我在 [What should go here?] 块中尝试了很多东西,但似乎无法让任何东西非常完美地工作。我最接近的是在这个块中使用以下内容:

(?!                     # 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>

看来我正在使用的前瞻并没有停止在 </Reference> 标记处,而是继续向下查看整个文件以确保它下面的文本没有“<SpecificVersion>False</SpecificVersion>”。

我怎样才能让我的前瞻停在它遇到的第一个“< /Reference>”,或者如果你有另一种方法来解决我的问题,我也愿意接受。任何建议表示赞赏。谢谢。

4

3 回答 3

3

放弃正则表达式。它注定了。不是 XML 吗?为什么不这样对待呢?

不要使用正则表达式解析 HTML ”规则同样适用于 XML。

于 2012-04-25T00:33:35.997 回答
2

无论如何,如果您想尝试正则表达式,我建议您这样做:

<Reference[^>]*?>(?:.(?!</Reference>))*?<SpecificVersion>([^<]*?)</SpecificVersion>

它匹配内部有标签的所有标签 - 即它将完全忽略任何没有标签的参考标签。

  • 它寻找参考标签
  • 匹配所有不是结束引用标记的内容,直到找到该标记
  • 然后它捕获标签内的值

我在正则表达式中对其进行了在线测试,它似乎在多种情况下都能正常工作。

编辑:

  • 使用 RegexOptions.Singleline 使点匹配新行

如果您想匹配 SpecificVersion 标签根本不存在的情况,请尝试此更改 - 它会尝试将选项与标签匹配,但如果失败,它仍将匹配

<Reference[^>]*?>(?:.(?!</Reference>))*?(<SpecificVersion>([^<]*?)</SpecificVersion>)|<Reference[^>]*?>(?:.(?!</Reference>))*?(?:<SpecificVersion>([^<]*?)</SpecificVersion>)?

让我知道你的进展如何。

于 2012-04-25T12:27:17.487 回答
0

因此,按照花费者的建议,我研究了正则表达式的替代方案。我发现了 Linq To XML,它使解决我的问题变得非常容易。这是我最终用来解决问题的代码。它查找 .csproj 文件中对 IQ DLL 文件的所有引用,并确保它们都具有 <SpecificVersion>False</SpecificVersion> 元素。只是为了一些背景信息,我需要这样做的原因是,当特定版本设置为 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");
}
于 2012-04-27T15:35:56.240 回答