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

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

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

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

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

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

不,没有那样的。

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

这两种解决方案在某些情况下都会“获胜”,而在其他情

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

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

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

C#中没有任何内容可以为您提供所需的开箱即用function。

想要的是一个Rope数据结构 ,一个支持O(1)concats和O(log n)子串的不可变数据结构。 我找不到任何绳索的C#实现,但这里是一个Java 。

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

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

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

 string text = myCheapObject; 

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

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