2016-05-13 94 views
3

我想使用这个表达式:什么导致这个正则表达式匹配一切?

^(\s+)<ProjectReference(.|\s)+?(Project2)</Name>(.|\s)+?</ProjectReference> 

...定位仅此节:

<ProjectReference Include="..\..\Project2\Project2.csproj"> 
     <Project>{6c2a7631-8b47-4ae9-a68f-f728666105b9}</Project> 
     <Name>Project2</Name> 
    </ProjectReference> 

...以下文件:

what is causing this text up here to be selected?? 

    <ProjectReference Include="..\..\Project1\Project1\Project1.csproj"> 
     <Project>{714c6b26-c609-40a4-80a9-421bd842562d}</Project> 
     <Name>Project1</Name> 
    </ProjectReference> 


    <ItemGroup> 
    <ProjectReference Include="..\..\Project2\Project2.csproj"> 
     <Project>{6c2a7631-8b47-4ae9-a68f-f728666105b9}</Project> 
     <Name>Project2</Name> 
    </ProjectReference> 
    <ProjectReference Include="..\..\Project3\Project3\Project3.csproj"> 
     <Project>{39860208-8146-429f-a1d1-5f8ed2fd7f5f}</Project> 
     <Name>Project3</Name> 
    </ProjectReference> 
    <ProjectReference Include="..\..\Project4\Project4.csproj"> 
     <Project>{58144d60-19d9-4d11-8ae6-088e03ccf874}</Project> 
     <Name>Project4</Name> 
    </ProjectReference> 
    <ProjectReference Include="..\..\Project5\Project5.csproj"> 
     <Project>{33baa509-ad24-4a72-a2fc-8f297e75e90d}</Project> 
     <Name>Project5</Name> 
    </ProjectReference> 
    </ItemGroup> 
    <PropertyGroup> 
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> 
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> 
    </PropertyGroup> 

在记事本++ ,它似乎最初找到了比赛,但随后在第二场比赛中继续匹配整个文档(所以它总共找到2场比赛)。我最初在我的.NET应用程序中发现了这一点,当时我的工具用一个空字符串替换了我的项目文件的全部内容,从而有效地清除了整个事情。

我已经花了一个多小时辛苦了,所以让我们来看看SE能否算出来。

更新:虽然我标志着实际工作的答案,我结束了一个不那么神奇的方法去确保没有罕见的正则表达式怪癖蔓延到我的代码后的道路为当时情况最近。

^(\s+)<ProjectReference.+?({0})\.(csproj|vbproj).*\r\n.*\r\n\s+<Name>{0}</Name>\r\n\s*</ProjectReference> 

...其中{0}是我的项目名称。虽然更详细,但这种解决方案不太可能出现过度匹配。我在我的.NET应用中使用了RegexOptions.Multiline,这样我就可以锚定到一行的开头。

+0

这个'(。| \ r \ n)+'。贪婪的''将捕获一切。 –

+0

@BoristheSpider糟糕,编写我的问题时出错。我用'?'纠正了它,但它仍然在做同样的事情。我直接从Notepad ++查找窗口中复制并粘贴该正则表达式。 – oscilatingcretin

+1

看来你想提取与'project2'相关的部分。为什么不使用xpath表达式或xml解析器? –

回答

3

我认为最好的方法是使用xpath表达式xml解析器

然而,当你在你的评论,如果你想使用正则表达式来捕获特定部分陈述,那么你可以使用这个:

(<ProjectReference.*?Project2[\s\S]*?</ProjectReference>) 

Working demo

匹配信息

MATCH 1 
1. [209-384] `<ProjectReference Include="..\..\Project2\Project2.csproj"> 
     <Project>{6c2a7631-8b47-4ae9-a68f-f728666105b9}</Project> 
     <Name>Project2</Name> 
    </ProjectReference>` 

除了regex101还使用SublimeText来显示它的工作,但Notepad ++有一个很差的正则表达式发动机和通常的招数弄乱它像[\s\S]*?

enter image description here

在另一方面,关系到你的问题有关“为什么失败”,你的正则表达式是不是失败但你的模式允许greedy比赛(偶用懒惰运营商),因为你的(.|\s)交替:

^(\s+)<ProjectReference(.|\s)+?(Project2)</Name>(.|\s)+?</ProjectReference> 
          ^--- HERE 

如果您检查Regex101 explanation,你可以看到:

2nd Capturing group (.|\s)+? 
    Quantifier: +? Between one and unlimited times, as few times as possible, expanding as needed [lazy] 
    Note: A repeated capturing group will only capture the last iteration. Put a capturing group around the repeated group to capture all iterations or use a non-capturing group instead if you're not interested in the data 
    1st Alternative: . 
    . matches any character (except newline) 
    2nd Alternative: \s 
    \s match any white space character [\r\n\t\f ] 
+0

您正在使用'Include'元素中的'Project2'作为标记,而OP使用''元素中的那个。这使得任务更简单,但你能确定它是有效的吗? –

+0

@AlanMoore,好眼睛,没有看到那个。我基于OP的目标来获取。让我们看看OP说什么,也许使用Include元素作为标记是很好的去。 –

+0

@AlanMoore您的解决方案同时适用于Notepad ++和我的.NET应用程序。我非常喜欢'[\ s \ S]'技巧。将来,我可能不会尝试所有这些正则表达式的魔法,只是采取更直接的方法,我会在我的问题结束后发布。 – oscilatingcretin

2

首先,从不使用(.|\s)来匹配所有内容 - 包括换行符;这是等待发生的冻结(更多信息请参见this answer)。Notepad ++中的搜索对话框包含一个用于此目的的复选框,标记为. matches newline

其次,无论如何,你都不应该得到那样的结果。我将它复制到Notepad ++的本地副本中,看起来像一个错误。也许正则表达式冻结,并且NPP没有发现错误。无论如何,你应该得到只有一个匹配,这就是发生在我选择. matches newline,改变你的正则表达式是:

^\h*<ProjectReference.*?Project2</Name>.*?</ProjectReference> 

但是,它仍然匹配太多,既包括Project1Project2元素。这是因为非贪婪的量词只影响匹配结束,而不是它开始的地方。您需要使用更具体的内容来确保匹配不会超出其开始的元素。我认为这是做到这一点的最可靠的方法:

^\h*<ProjectReference(?:(?!</?ProjectReference).)*Project2</Name>.*?</ProjectReference> 

的想法是,该点是允许任何匹配字符(包括新行),除非它的序列<ProjectReference</ProjectReference的第一个字符。因此,一旦它开始匹配开头<ProjectReference>标签,它就可以匹配除另一个此类标签(开头或结束)以外的任何内容,直到找到标识字符串(Project2)。

更新:这肯定是Notepad ++中的一个错误。我自己做了更多的测试,并发现其他报告来确认它(herehere)。那些家伙在试图触发这个bug方面非常有创意,但归结起来就是:如果正则表达式需要很长时间才能匹配,那么NPP会错误地选择一切。

+0

我在Notepad ++中试过了你的第二个正则表达式,它可以工作,但是我必须''。匹配换行符“启用。这个问题最初是在我的.NET应用程序中发现的,所以我需要一个在那里工作的解决方案。 .NET本机正则表达式选项仅支持'RegexOptions.Multiline',它与Notepad ++的选项不同。不过,我赞成你的回答。我找到了一个解决方案,它采取更为直接的方法,而不是试图完成所有这些正则表达式魔法来匹配神奇的模式。我将很快发布 – oscilatingcretin

+0

对不起,我认为Notepad ++是您的目标口味。在.NET中,你必须使用'Multiline'模式在行的开头匹配'^'(NPP *总是*多行模式),'Singleline'使'.'匹配换行符。另外,.NET中不支持'\ h'(水平空格),所以要么使用'[\ t *]',要么使用'\ s *'。或者完全放弃它;除非你试图规范领先的空白,否则这个部分是没有必要的。 –

+0

.NET中SingleLine模式的问题在于,根据我的测试,它将整个sting视为单行字符串,因此不能使用'^锚定到字符串中间的行。 – oscilatingcretin

相关问题