2009-06-16 102 views
3

這可能嗎?考慮到C#使用不可改變的字符串,可以預期會有沿着線的方法:在C#字符串對象之間共享字符緩衝區

var expensive = ReadHugeStringFromAFile(); 
var cheap = expensive.SharedSubstring(1); 

如果沒有這樣的功能,所以有做串不可變麻煩? 或者,如果字符串由於其他原因已經不可變,爲什麼不提供這種方法?

我正在研究這個問題的具體原因是做一些文件解析。簡單的遞歸下降解析器(例如TinyPG生成的解析器,或者手工編寫的解析器)在整個地方使用Substring。這意味着如果你給他們一個大文件解析,內存流失是難以置信的。當然有一些解決方法 - 基本上是自己編寫SubString類,然後當然忘記了可以使用String方法,比如StartsWith或者Regex等字符串庫,所以你也需要推出自己的版本。我認爲ANTLR這樣的解析器生成器基本上是這樣做的,但是我的格式很簡單,不足以證明使用這樣的怪物工具是合理的。即使TinyPG可能是一個過度殺傷力。

有人請告訴我,我錯過了一些明顯或不那麼明顯的標準的C#方法調用的地方...

+0

我剛剛測試了一個潛在的解決方法。解決問題的一種方法是能夠將正則表達式匹配到字符串的中間。如果您將「^。{N}」附加到正則表達式的開頭,這是可能的。然而,似乎正則表達式庫在一次操作中不夠聰明,只能跳過N個字符。它需要O(N)時間,所以隨着N的增長,匹配開始花費更長和更長的時間。嘆。 – 2009-06-16 22:00:52

+0

哈,當然Regex.Match有一個可選的startat參數,顯然是O(1)。所以解決方法畢竟工作。我不會說這是一個乾淨的解決方案,但它會做... – 2009-06-16 22:04:06

回答

5

沒有,有沒有這樣的。

.NET串直接包含其文本數據,不同於具有到字符數組,偏移和長度的參考Java字符串。

這兩種解決方案在某些情況下都有「勝利」,在其他情況下也有損失。

如果你絕對是肯定這對你來說是一個殺手,你可以實現一個Java風格的字符串以用於你自己的內部API。

+0

這就是我害怕的。嘆。謝謝... – 2009-06-16 21:35:52

+0

啊,今天早些時候我只是在想這個。 – 2009-06-16 21:59:44

1

的.NET框架支持string interning。這是一個部分解決方案,但不提供重用字符串部分的可能性。我認爲重用substring會導致一些問題,而不是一開始就會出現的問題。如果你必須使用StringBuilder做很多字符串處理,那麼這是一條可行的路。

+0

字符串interning(在Java和C#中)都是大腦死亡的,因爲它需要您在調用Intern之前構造一個字符串對象。對於具有節省內存使用的目的的東西,你期望能夠傳遞給它一個StringBuilder或一個(切片)字符數組或類似的東西。但是,不,「這太容易了」。 – 2009-06-16 21:25:26

+0

這是真的......但GC ...:D – 2009-06-16 21:30:15

2

據我所知,所有較大的解析器都使用流來解析。這不適合你的情況嗎?

0

在C#中沒有爲您提供您正在尋找的出的現成功能。

什麼要的是Rope data structure,它支持O(1)concats和O(log n)的子串的不可變數據結構。我找不到任何C#實現的繩索,但是here a Java one

除非是,沒有什麼錯誤使用TinyPG或ANTLR,如果這是爲了把事情做好最簡單的方法。

0

那麼你可以使用「不安全」做內存管理自己,這可能讓你做你在找什麼。此外,StringBuilder類非常適合需要多次操作字符串的情況,因爲它不會爲每次操作都創建一個新字符串。

0

你可以很容易地寫一個簡單的類來表示「便宜」。它只會保存子串的開始索引和子串的長度。一對夫婦的方法將允許您在需要時讀出的子串 - 一個字符串轉換運算將是理想的,因爲你可以使用

string text = myCheapObject; 

,它將無縫工作就好像它是一個實際的字符串。增加對StartsWith這些方便的方法的支持將會很快且簡單(它們都是一行)。

另一種選擇是編寫常規解析器並將您的標記存儲在您從中共享對標記的引用的字典中,而不是保留多個副本。