2010-08-17 60 views
19

我正在將文本文件的內容寫入到StringBuilder中,然後我想使用正則表達式對StringBuilder中包含的文本執行一些查找/替換操作。StringBuilder中的正則表達式替換

由於StringBuilder替換函數不能接受正則表達式參數,所以我遇到了問題。

我可以在普通的字符串上使用Regex.Replace,但我的印象是效率低下,因爲需要在內存中創建兩個字符串副本,因爲.net字符串是不可變的。

一旦我更新了文本,我打算將它重新寫回原始文件。

什麼是解決我的問題最好最有效的方法?

編輯

除了答案(S)以下時,我發現了以下問題,這也闡明我的問題的一些光 -

回答

23

最好和最有效的解決方案爲您的時間首先嚐試最簡單的方法:忘記StringBuilder並只使用Regex.Replace。然後找出它的速度有多慢 - 它可能非常好。不要忘記在編譯和非編譯模式下嘗試正則表達式。

如果不是足夠快,可以考慮使用你可以簡單地表達任何替換一個StringBuilder,然後用Regex.Replace爲休息。您可能還想考慮嘗試組合替換,從而減少使用的正則表達式(以及中間字符串)的數量。

+1

我很驚訝我沒有想到這個:實際運行它,看看,而不是猜測速度會是什麼。我相應地刪除了我的推測性答案。 – Timwi 2010-08-17 16:53:04

+1

如果Regex.Replace足夠快,我是否應該對內存管理給予任何關注?我是否在分析/優化內容時擔心存儲空間不足以創建多個字符串? – ipr101 2010-08-17 17:38:29

+0

這不是一個答案,而是一個建議。問題是如何讓正則表達式使用stringbuilder工作,答案是它們不兼容,除非你編寫自己的實現。爲什麼這是我不知道的情況。 – Slight 2015-06-01 14:11:30

1

我不確定這是否有助於您的場景,但我遇到了Regex的一些內存消耗限制,我需要一個簡單的通配符替換擴展方法在StringBuilder上推過去。如果你需要複雜的正則表達式匹配和/或反向引用,這不會做,但如果簡單*或?通配符替代(用文字「替換爲」文本)會得到這份工作給你我的問題的最終完成,那麼解決辦法在這裏至少應該給你一個刺激:

Has anyone implemented a Regex and/or Xml parser around StringBuilders or Streams?

0

這裏是一個擴展方法你可以用來完成你想要的。它需要一個Dictionary其中的關鍵是你正在尋找的模式,價值是你想要替換它。您仍然創建傳入字符串的副本,但您只需處理一次,而不是爲Regex.Replace多次調用創建副本。

public static StringBuilder BulkReplace(this StringBuilder source, IDictionary<string, string> replacementMap) 
{ 
    if (source.Length == 0 || replacementMap.Count == 0) 
    { 
     return source; 
    } 
    string replaced = Regex.Replace(source.ToString(), String.Join("|", replacementMap.Keys.Select(Regex.Escape).ToArray()), m => replacementMap[m.Value], RegexOptions.IgnoreCase); 
    return source.Clear().Append(replaced); 
} 
+1

在StringBuilder中使用正則表達式不僅僅是爲了實現這個工作,而是爲了最大限度地減少內存浪費,特別是避免大量的中間字符串被存儲在內存中。 – 2014-07-30 02:56:33

+0

這並不完美,因爲您必須將StringBuilder轉換爲字符串,但這種方法比簡單地對字符串重複調用Regex.Replace大約快4倍。 – 2014-07-31 12:43:28

+0

如果replacementMap包含模式,您將得到:「給定的密鑰不在字典中」。這是預期的,因爲來自replacementMap [m.Value]的m.Value尋找一個鍵,該鍵是由模式匹配的actula字符串,而不是模式本身。我錯過了什麼嗎?通過模式我的意思是正則表達式模式字符串,如:「」<[^>] +>「而不是像」
mmmmmm 2015-11-05 08:10:45

2

你有3種選擇:

  1. 這樣做是用繩子一個低效的方式,正如其他人推薦這裏。

  2. 使用.Matches()呼叫您的Regex對象,並模擬.Replace()的工作方式(請參閱#3)。

  3. 適應單執行Regex建立一個Regex接受StringBuilder(並請在這裏分享吧!),幾乎所有的工作都已經爲你單做,但它需要時間來蘇斯出來的零件是使其工作到自己的圖書館。 Mono的Regex充分利用了Novell 2002年的JVM實現Regex

在單聲道:

System.Text.RegularExpressions.Regex使用一個RxCompilerRxInterpreterFactory的形式,其意料之中使得IMachine S作爲RxInterpreter s至實例化一個IMachineFactory。讓它們發出是你需要做的大部分事情,但是如果你只是想了解它的結構是如何提高效率的,那麼你要找的很多東西都在它的基類BaseMachine中。

特別是,在BaseMachine是基於StringBuilder的東西。在方法LTRReplace中,它首先使用初始字符串實例化一個StringBuilder,從此開始的所有內容純粹是基於StringBuilder的。實際上,如果我們假設內部Microsoft .Net實現類似,那麼Regex沒有將StringBuilder方法放在外面,這實際上很煩人。

盤旋迴建議2,你可以通過調用.Matches(),跟蹤您身在何處原始字符串和循環模仿LTRReplace的行爲:

var matches = regex.Matches(original); 
var sb = new StringBuilder(original.Length); 
int pos = 0; // position in original string 
foreach(var match in matches) 
{ 
    sb.Append(original.Substring(pos, match.Index)); // Append the portion of the original we skipped 
    pos = match.Index; 

    // Make any operations you like on the match result, like your own custom Replace, or even run another Regex 

    pos += match.Value.Length; 
} 
sb.Append(original.Substring(pos, original.Length - 1)); 

但是,這不僅節省了你一些字符串 - 的mod-Mono方法是唯一真正做到這一點的人。