在C#字符串对象之间共享字符缓冲区

时间:2009-06-16 21:00:56

标签: c# parsing memory-management substring

这可能吗?鉴于C#使用不可变字符串,人们可以预期会有一个方法:

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

如果没有这样的功能,为什么还要使字符串不变? 或者,如果字符串由于其他原因已经不可变,为什么不提供此方法?

我正在调查的具体原因是进行一些文件解析。简单的递归下降解析器(例如由TinyPG生成的解析器,或者易于手工编写的解析器)在整个地方使用Substring。这意味着如果你给他们一个大文件来解析,内存流失是令人难以置信的。当然有解决方法 - 基本上是滚动你自己的SubString类,然后当然忘记了能够使用诸如StartsWith之类的String方法或者像Regex这样的字符串库,所以你需要自己推出这些版本。我假设像ANTLR这样的解析器生成器基本上就是这样做的,但我的格式很简单,不能证明使用这样的怪物工具。即使是TinyPG也可能是一种矫枉过正的行为。

有人请告诉我,我错过了一些明显或不那么明显的标准C#方法调用...

6 个答案:

答案 0 :(得分:5)

不,没有那样的。

.NET字符串直接包含其文本数据,不像Java字符串,它引用了char数组,偏移量和长度。

在某些情况下,这两种解决方案都有“胜利”,而在其他情况下则有损失。

如果您绝对确定这对您来说是一个杀手,您可以实现一个Java风格的字符串,以便在您自己的内部API中使用。

答案 1 :(得分:2)

据我所知,所有较大的解析器都使用流来解析。那不适合你的情况吗?

答案 2 :(得分:1)

.NET框架支持string interning。这是部分解决方案,但不提供重用字符串部分的可能性。我认为重用子字符串会导致一些问题,而不是第一眼看到的问题。如果你必须使用StringBuilder进行大量的字符串操作,那么就可以了。

答案 3 :(得分:0)

C#中没有任何内容为您提供您正在寻找的开箱即用功能。

需要什么是Rope data structure,一个支持O(1)concats和O(log n)子串的不可变数据结构。我找不到绳索的任何C#实现,但是here a Java one

除此之外,使用TinyPG或ANTLR没有任何问题,如果这是完成任务的最简单方法。

答案 4 :(得分:0)

嗯,你可以使用“不安全”自己做内存管理,这可能会让你做你想要的。此外,StringBuilder类非常适合需要多次操作字符串的情况,因为它不会在每次操作时生成新的字符串。

答案 5 :(得分:0)

您可以轻松编写一个简单的类来表示“便宜”。它只会保存子字符串开头的索引和子字符串的长度。有两种方法可以让你在需要时读出子串 - 一个字符串强制转换操作符是理想的,因为你可以使用

string text = myCheapObject;

它可以无缝地工作,就好像它是一个实际的字符串。添加对一些方便的方法(如StartsWith)的支持将是快速而简单的(它们都是一个衬里)。

另一种选择是编写一个常规解析器并将您的标记存储在一个字典中,您可以从该字典中共享对标记的引用,而不是保留多个副本。