2009-06-16 72 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这些方便的方法的支持将会很快且简单(它们都是一行)。

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