2016-05-13 89 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

相關問題