如何使用正则表达式不与包含多行模式中间特定文本的文本匹配

本文关键字:文本 中间 模式 正则表达式 何使用 包含多 | 更新日期: 2023-09-27 18:32:20

我正在尝试创建一个 C# 正则表达式,用于检测我们的 .csproj 文件中的引用何时没有<将 SpecificVersion=">设置为 False(必须在所有

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>

所以基本上任何没有明确包含"False"的文件引用。

因此,让我们忽略第一种情况,因为它不像其他 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>

似乎我正在使用的前瞻性并没有停留在 标签上,而是继续向下查看整个文件,以确保它下面的文本没有"False"。

我怎样才能让我的展望在它遇到的第一个"时停止,或者如果您有另一种方法来解决我的问题,我也对此持开放态度。 任何建议不胜感激。 谢谢。

如何使用正则表达式不与包含多行模式中间特定文本的文本匹配

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

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

如果你想尝试一下正则表达式,我会建议这样的东西:

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

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

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

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

编辑:

  • 使用正则表达式选项.单行使点匹配新行

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

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

让我知道你过得怎么样。

因此,按照spender的建议,我研究了正则表达式的替代方案。我发现了 Linq To XML,它使解决我的问题变得非常容易。 这是我结束用来解决我的问题的代码。 它在 .csproj 文件中查找对 IQ DLL 文件的所有引用,并确保它们都具有 False 元素。仅出于一些背景信息,我需要这样做的原因是,当"特定版本"设置为 True 时,我们的生成在本地计算机上运行良好,但除非设置为 False,否则它会在我们的 TFS 生成服务器上中断。我很确定这样做的原因是我们的 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");
}