2009-01-08 40 views
1

我不認爲這是可能的只是正則表達式,但我不是專家,所以我認爲這是值得問。正則表達式lookaround

我試圖做一個大規模的搜索和替換C#代碼,使用.NET正則表達式。我想要做的是找到一行代碼,其中在DateTime類型的變量上調用特定函數。例如:

axRecord.set_Field("CreatedDate", m_createdDate); 

,我也知道這是在代碼文件中較早日期時間變量B/C是行:

DateTime m_createdDate; 

但似乎我不能使用命名組像負回顧後:

(?<=DateTime \k<1>.+?)axRecord.set_[^ ]+ (?<1>[^)]+) 

,如果我嘗試將變量聲明和函數調用這樣的所有文本匹配:

DateTime (?<1>[^;]+).+?axRecord.set.+?\k<1> 

會找到它的第一場比賽 - 第一款基於第一個變量聲明 - ,但隨後無法找到任何其他比賽中,因爲代碼佈局是這樣的:

DateTime m_First; 
DateTime m_Second; 
... 
axRecord.set_Field("something", m_First); 
axRecord.set_Field("somethingElse", m_Second); 

和第一場比賽包含第二個變量聲明。

是否有一種很好的方法只用正則表達式來做到這一點,還是我必須訴諸於我的邏輯腳本?

回答

0

試試這個:

@"(?s)set_Field\(""[^""]*"",\s*(?<vname>\w+)(?<=\bDateTime\s+\k<vname>\b.+)" 

通過首先做回顧後,你迫使正則表達式搜索的方法,在特定的順序調用:在該變量聲明的順序。你想要做的是首先匹配一個看起來很可能的方法調用,然後使用lookbehind來驗證變量的類型。

我只是粗略地猜測了匹配方法調用的部分。就像其他人所說的那樣,無論你使用哪種正則表達式,都必須根據你的代碼量身定製;沒有通用的解決方案。

1

這對單個正則表達式很難做到。但是,如果考慮處理具有一些狀態的行,則可以這樣做。

注:我不能告訴你想匹配的axRecord線到底是什麼,所以你很可能需要適當調整該正則表達式。

void Process(List<string> lines) { 
    var comp = StringComparer.Ordinal; 
    var map = new Hashset<string>comp); 
    var declRegex = new Regex("^\s(?<type>\w+)\s*(?<name>m_\w+)\s*";); 
    var toReplaceRegex = new Regex("^\s*axRecord.set_(?<toReplace>.*(?<name>m_\w+).*)"); 

    for(var i = 0; i < lines.Length; i++) { 
    var line = lines[i]; 
    var match = declRegex.Match(line); 
    if (match.Success) { 
     if (comp.Equals(match.Groups["type"], "DateTime")) { 
     map.Add(comp.Groups["name"]); 
     } else { 
     map.Remove(comp.Groups["name"]); 
     } 
     continue; 
    } 

    match = toReplaceRegex.Match(line); 
    if (match.Success && map.Contains(match.Groups["name"])) { 
     // Add your replace logic here 
    } 
} 
+0

這是一個很好的解決方案,但對於第二天左右,除非Jan Goyvaerts進來並說這是不可能的,否則我會認爲它是:) – LoveMeSomeCode 2009-01-08 18:35:09

+0

@LoveMeSomeCode,這是一個臨界不可能的問題。考慮到這一點,如果你想讓它在任何C/C#代碼中100%的時間內工作,用正則表達式是不可能的。正則表達式不如解析器強大。另一方面,如果你想在你的特定項目中的代碼解決方案,它可能是 – JaredPar 2009-01-08 19:09:33

0

這不能用正則表達式來完成。一方面,C#的語法不規則;但更重要的是,你正在談論分析詞彙無關的表達式。對於這類事情,你將需要完整的語義分析。這意味着詞法分析器,解析器,名稱綁定以及類型檢查器。一旦你有註釋的AST,你可以尋找你想要的領域,只是讀取類型。

我猜這是一個很大的工作,不是你想要做雖然,看到它大約半一個完全成熟的C#編譯器。

+0

看到我的答案,你可以在VS上捎帶,並在EnvDTE對象 – 2009-01-08 17:24:16

5

看一看我回答這個問題Get a methods contents from a C# file

它提供鏈接到介紹如何使用內置的.NET語言解析器來簡單可靠地(做這個網頁即不問「是什麼樣子我正在搜索的用法「,但通過使用VS代碼解析工具正確解析代碼)。

我知道這不是RegEx的答案,但我不認爲RegEx是答案。

0

這很奇怪。我設法構建了一個可以找到它的正則表達式,但它只匹配第一個。

(?<=private datetime (?<1>\b\w+\b).+?)set_field[^;]+?\k<1> 

所以好像如果我不能在回顧後使用命名組,我至少可以建立一個名爲組中的回顧後,並在比賽中使用它。但是,它看起來像只匹配函數調用時(這是我想要的),插入符的位置移動到那一行,因此它無法找到任何新匹配,因爲它已通過它們的聲明。或者我不明白引擎是如何工作的。

我想我正在尋找的是一個正則表達式選項,它告訴它查看更多匹配的內部匹配。這似乎是基本的HTML正則表達式分析所需要的。你找到一個標籤,然後它結束標籤,並且整個頁面被包含在該匹配中,除非遞歸地將該模式應用於每個匹配,否則不會找到任何其他標籤。

任何人都知道這件事或者我說瘋了嗎?

+0

中免費獲得所有這些,實際上這個模式將匹配一個函數最後聲明的變量。即它回溯到聲明,並且它發現的第一個讓背後看起來是真實的。刪除? lookbehind中的懶操作符將其切換到第一個聲明的變量。 – LoveMeSomeCode 2009-01-08 18:40:21