C# 在不创建额外内存的情况下反转字符串
我有一个大约1mb大小的字符串。要求在不分配另一个大小为1MB的临时字符串的情况下反转该字符串。我尝试了以下代码C# 在不创建额外内存的情况下反转字符串,c#,C#,我有一个大约1mb大小的字符串。要求在不分配另一个大小为1MB的临时字符串的情况下反转该字符串。我尝试了以下代码 string name = "abcde"; string target = ""; for(int i = name.Length - 1; i >=0; i--) { target += name[i]; name = name.Remove(i); int n = name.Length; } 但是我的朋友说,如
string name = "abcde";
string target = "";
for(int i = name.Length - 1; i >=0; i--)
{
target += name[i];
name = name.Remove(i);
int n = name.Length;
}
但是我的朋友说,如果我们使用函数
name.Remove(i)
,它将返回一个新字符串,但不能保证旧字符串会从内存中删除,因此不能保证大小会减小。这是真的吗?如果有其他选项可以在不分配额外内存的情况下反转一个字符串吗?< P>编辑:完全失去了情节,最近使用C++太多了,我忘记了C字符串是不可变的。
简而言之,您必须分配新内存来更改C#中的字符串。您可以通过以下方式以最直接的方式完成此操作:
string ReverseString(string value)
{
if (!string.IsNullOrEmpty(value))
{
char[] newBuffer = new char[value.Length];
for(int i = 0; i < value.Length; i++)
newBuffer[newBuffer.Length - i - 1] = value[i];
value = new string(newBuffer);
}
return value;
}
static IEnumerable<Tuple<int, int>> GetTextElementSegments(string value)
{
int[] elementOffsets = StringInfo.ParseCombiningCharacters(value);
int lastOffset = -1;
foreach (int offset in elementOffsets)
{
if (lastOffset != -1)
{
int elementLength = offset - lastOffset;
Tuple<int, int> segment = new Tuple<int,int>(lastOffset, elementLength);
yield return segment;
}
lastOffset = offset;
}
if (lastOffset != -1)
{
int lastSegmentLength = value.Length - lastOffset;
Tuple<int, int> segment = new Tuple<int, int>(lastOffset, lastSegmentLength);
yield return segment;
}
}
static void Main(string[] args)
{
string input = "t\u0301e\u0302s\u0303t\u0304";
StringBuilder resultBuilder = new StringBuilder(input.Length);
var segments = GetTextElementSegments(input);
foreach (var segment in segments.Reverse())
{
resultBuilder.Append(input, segment.Item1, segment.Item2);
}
Debug.Assert(resultBuilder.ToString() == "t\u0304s\u0303e\u0302t\u0301s");
}
字符串反向限制(字符串值)
{
如果(!string.IsNullOrEmpty(值))
{
char[]newBuffer=new char[value.Length];
for(int i=0;i
这应该会有所帮助
string reverse = new string("ABCDEFGHI".ToCharArray().Reverse().ToArray());
字符串“abcde”在内存中是一个常量。你不能改变它,因为它是不变的。您需要的是创建一个新字符串,为此您需要新的内存。字符串是不可变的,如果不分配新内存,您就无法反转它
string name = "aaaaa":
name = name.Remove(0); // this is allocating new memory.
字符串是不可变的——不能更改字符串对象的内容
创建对象后更改,尽管语法使其
看起来好像你能做到这一点
从同一链接,请参见此示例:
string b = "h";
b += "ello";
还有解释
编写此代码时,编译器实际上会创建一个新字符串
对象来保存新的字符序列,并且该新对象是
分配给b。然后字符串“h”有资格进行垃圾收集
字符串是不可变的。当你申报时,你不能更改它。因此,无论您尝试什么,都将创建并使用新的内存
string name = "aaaaa":
name = name.Remove(0); // this is allocating new memory.
如果您对原始数据有一些控制权,您应该能够做到这一点。例如,如果您可以要求使用
char[]
,而无需创建字符串
,则可以在适当的位置将其反转
例如,在您的示例中,您可以使用var name=new char[]{'a','b','c','d','e'}
代替字符串,然后将其颠倒过来
(显然,对于1MB字符串,您不能这样做,但无论您从何处获取字符串,如果您最初可以将其作为char[]
加载…)
如果你只能有一个
字符串
,那你就倒霉了。它们是不可变的-您只能通过某种方式复制字符串来修改它。使用StringBuilder
您可以使用char数组进行手动操作,但不能使用string
,因为它是不可变的实际上,如果不至少分配与要反转的字符串占用的内存相同的内存量,就没有正确的方法来反转字符串。(从理论上讲,可以在内存中反转字符串,但这是不推荐的,我甚至不打算进入该区域)。现在我们来谈谈字符串本身的反转。我正在进行一个名为StringExtensions的小项目,在这个项目中,我试图解决使用字符串时可能出现的所有问题。最大的难题之一是UTF-16编码,该编码在整个框架中广泛使用。我的字符串反转实现如下所示:
string ReverseString(string value)
{
if (!string.IsNullOrEmpty(value))
{
char[] newBuffer = new char[value.Length];
for(int i = 0; i < value.Length; i++)
newBuffer[newBuffer.Length - i - 1] = value[i];
value = new string(newBuffer);
}
return value;
}
static IEnumerable<Tuple<int, int>> GetTextElementSegments(string value)
{
int[] elementOffsets = StringInfo.ParseCombiningCharacters(value);
int lastOffset = -1;
foreach (int offset in elementOffsets)
{
if (lastOffset != -1)
{
int elementLength = offset - lastOffset;
Tuple<int, int> segment = new Tuple<int,int>(lastOffset, elementLength);
yield return segment;
}
lastOffset = offset;
}
if (lastOffset != -1)
{
int lastSegmentLength = value.Length - lastOffset;
Tuple<int, int> segment = new Tuple<int, int>(lastOffset, lastSegmentLength);
yield return segment;
}
}
static void Main(string[] args)
{
string input = "t\u0301e\u0302s\u0303t\u0304";
StringBuilder resultBuilder = new StringBuilder(input.Length);
var segments = GetTextElementSegments(input);
foreach (var segment in segments.Reverse())
{
resultBuilder.Append(input, segment.Item1, segment.Item2);
}
Debug.Assert(resultBuilder.ToString() == "t\u0304s\u0303e\u0302t\u0301s");
}
静态IEnumerable GetTextElementSegments(字符串值)
{
int[]elementOffsets=StringInfo.ParseCombiningCharacters(值);
int lastOffset=-1;
foreach(元素偏移量中的整数偏移量)
{
如果(lastOffset!=-1)
{
int elementLength=offset-lastOffset;
元组段=新元组(lastOffset,elementLength);
收益率区间;
}
lastOffset=偏移量;
}
如果(lastOffset!=-1)
{
int lastSegmentLength=值。Length-lastOffset;
元组段=新元组(lastOffset,lastSegmentLength);
收益率区间;
}
}
静态void Main(字符串[]参数)
{
字符串输入=“t\u0301e\u0302s\u0303t\u0304”;
StringBuilder resultBuilder=新StringBuilder(input.Length);
var segments=GetTextElementSegments(输入);
foreach(段中的var段。Reverse())
{
resultBuilder.Append(输入,段.Item1,段.Item2);
}
Assert(resultBuilder.ToString()=“t\u0304s\u0303e\u0302t\u0301s”);
}
请注意,这会处理代理项对、unicode标记代码点,并且只分配与输入字符串本身占用的内存量相似的内存。如果您真的不想额外分配内存,则需要
修复字符串并使用不安全的指针代码。或者,使用反射获取对内部char[]
的引用
你真的不想这么做。真正地我是说,真的。请不要这样做,除非作为学习练习。如果人们在生产中发现这样的代码,他们可能会带着武器来找你
我不打算尝试编写这样的代码(因为我知道我会出错)。但这里有一些链接可以帮助您开始:
- -一篇很老的文章,但有最好的例子
- -对你想要的东西来说有点高,但这是一个好地方
开始
课程计划
{
静态void Main(字符串[]参数)
{
//注意我是如何不用变量的?
//这是一个肮脏的黑客知道编译器将实习的价值。
//破解BCL的诸多缺点之一。
while(string.IsNullOrWhiteSpace(Console.ReadLine()))
{
Console.WriteLine(“he\0llo”);
“he\0llo”。ReverseInPlace();
for (int i = textBox1.TextLength - 1; i >= 0; i--)
{
textBox1.Text += textBox1.Text[i];
}
textBox1.Text = textBox1.Text.Remove(0, textBox1.Text.Length / 2);
public static String reverseString(String str) {
return reverseStringXor(str.toCharArray(), 0, str.length() - 1);
}
private static String reverseStringXor(char[] str, int start, int end) {
while (start < end) {
str[start] ^= str[end];
str[end] ^= str[start];
str[start] ^= str[end];
start++;
end--;
}
return String.valueOf(str);
}