을 사용하여 문자열을 추가 할 수 있다는 것을 알고 있습니다 StringBuilder
. 제공 StringBuilder
하는 성능 이점을 유지할 수 있도록을 사용하여 문자열 앞에 추가 (즉, 문자열 앞에 문자열 추가) 할 수있는 방법이 StringBuilder
있습니까?
을 사용하여 문자열을 추가 할 수 있다는 것을 알고 있습니다 StringBuilder
. 제공 StringBuilder
하는 성능 이점을 유지할 수 있도록을 사용하여 문자열 앞에 추가 (즉, 문자열 앞에 문자열 추가) 할 수있는 방법이 StringBuilder
있습니까?
답변:
위치 매개 변수를 0으로 설정하고 삽입 방법을 사용하는 것은 앞에 추가하는 것과 같습니다 (즉, 시작 부분에 삽입).
예 : varStringBuilder.insert(0, "someThing");
많은 접두어가있는 고성능이 필요한 경우 고유 한 버전을 작성해야합니다 StringBuilder
(또는 다른 사람의 버전을 사용해야합니다). 표준 StringBuilder
(기술적으로는 다르게 구현 될 수 있지만)을 사용하면 삽입 지점 이후에 데이터를 복사해야합니다. n 개의 텍스트를 삽입하는 데 O (n ^ 2) 시간이 걸릴 수 있습니다.
순진한 접근 방식은 char[]
길이뿐만 아니라 백업 버퍼에 오프셋을 추가하는 것 입니다. 앞에 추가 할 공간이 충분하지 않은 경우 꼭 필요한 것 이상으로 데이터를 위로 이동하십시오. 이것은 성능을 다시 O (n log n) (제 생각에)로 낮출 수 있습니다. 보다 세련된 접근 방식은 버퍼를 주기적으로 만드는 것입니다. 이러한 방식으로 어레이의 양쪽 끝에있는 여유 공간이 연속됩니다.
확장 방법을 시도해 볼 수 있습니다.
/// <summary>
/// kind of a dopey little one-off for StringBuffer, but
/// an example where you can get crazy with extension methods
/// </summary>
public static void Prepend(this StringBuilder sb, string s)
{
sb.Insert(0, s);
}
StringBuilder sb = new StringBuilder("World!");
sb.Prepend("Hello "); // Hello World!
나는 그것을 사용하지 않았지만 Ropes For Java Sounds는 흥미 롭습니다. 프로젝트 이름은 단어 놀이입니다 . 진지한 작업을 위해 문자열 대신 로프 를 사용하십시오 . 준비 및 기타 작업에 대한 성능 저하를 피합니다. 이 일을 많이한다면 한 번 볼 가치가 있습니다.
로프는 Strings의 고성능 대체품입니다. "로프 : 문자열의 대안"에 자세히 설명 된 데이터 구조는 접두사, 추가, 삭제 및 삽입과 같은 일반적인 문자열 수정에 대해 String 및 StringBuffer보다 점근 적으로 더 나은 성능을 제공합니다. 문자열과 마찬가지로 로프는 불변이므로 다중 스레드 프로그래밍에 사용하기에 적합합니다.
Insert ()를 사용해보십시오
StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!
다른 의견을 고려할 때이를 수행하는 표준 빠른 방법이 없습니다. StringBuilder .Insert(0, "text")
를 사용하는 것은 고통스럽게 느린 String 연결 (> 10000 개의 연결을 기반으로 함)을 사용하는 것보다 약 1-3 배 빠르므로 다음은 잠재적으로 수천 배 더 빨리 앞에 추가하는 클래스입니다!
나는 다음과 같은 몇 가지 다른 기본적인 기능을 포함 시켰습니다 append()
, subString()
그리고 length()
등 모두 추가하고 앞에 추가 느린의 StringBuilder가 추가보다 3 배 약 두 배 빠른 다릅니다. StringBuilder와 마찬가지로이 클래스의 버퍼는 텍스트가 이전 버퍼 크기를 오버플로 할 때 자동으로 증가합니다.
코드는 꽤 많이 테스트되었지만 버그가 없다고 보장 할 수는 없습니다.
class Prepender
{
private char[] c;
private int growMultiplier;
public int bufferSize; // Make public for bug testing
public int left; // Make public for bug testing
public int right; // Make public for bug testing
public Prepender(int initialBuffer = 1000, int growMultiplier = 10)
{
c = new char[initialBuffer];
//for (int n = 0; n < initialBuffer; n++) cc[n] = '.'; // For debugging purposes (used fixed width font for testing)
left = initialBuffer / 2;
right = initialBuffer / 2;
bufferSize = initialBuffer;
this.growMultiplier = growMultiplier;
}
public void clear()
{
left = bufferSize / 2;
right = bufferSize / 2;
}
public int length()
{
return right - left;
}
private void increaseBuffer()
{
int nudge = -bufferSize / 2;
bufferSize *= growMultiplier;
nudge += bufferSize / 2;
char[] tmp = new char[bufferSize];
for (int n = left; n < right; n++) tmp[n + nudge] = c[n];
left += nudge;
right += nudge;
c = new char[bufferSize];
//for (int n = 0; n < buffer; n++) cc[n]='.'; // For debugging purposes (used fixed width font for testing)
for (int n = left; n < right; n++) c[n] = tmp[n];
}
public void append(string s)
{
// If necessary, increase buffer size by growMultiplier
while (right + s.Length > bufferSize) increaseBuffer();
// Append user input to buffer
int len = s.Length;
for (int n = 0; n < len; n++)
{
c[right] = s[n];
right++;
}
}
public void prepend(string s)
{
// If necessary, increase buffer size by growMultiplier
while (left - s.Length < 0) increaseBuffer();
// Prepend user input to buffer
int len = s.Length - 1;
for (int n = len; n > -1; n--)
{
left--;
c[left] = s[n];
}
}
public void truncate(int start, int finish)
{
if (start < 0) throw new Exception("Truncation error: Start < 0");
if (left + finish > right) throw new Exception("Truncation error: Finish > string length");
if (finish < start) throw new Exception("Truncation error: Finish < start");
//MessageBox.Show(left + " " + right);
right = left + finish;
left = left + start;
}
public string subString(int start, int finish)
{
if (start < 0) throw new Exception("Substring error: Start < 0");
if (left + finish > right) throw new Exception("Substring error: Finish > string length");
if (finish < start) throw new Exception("Substring error: Finish < start");
return toString(start,finish);
}
public override string ToString()
{
return new string(c, left, right - left);
//return new string(cc, 0, buffer); // For debugging purposes (used fixed width font for testing)
}
private string toString(int start, int finish)
{
return new string(c, left+start, finish-start );
//return new string(cc, 0, buffer); // For debugging purposes (used fixed width font for testing)
}
}
간단한 클래스를 사용하여 StringBuilder에 대한 확장을 직접 만들 수 있습니다.
namespace Application.Code.Helpers
{
public static class StringBuilderExtensions
{
#region Methods
public static void Prepend(this StringBuilder sb, string value)
{
sb.Insert(0, value);
}
public static void PrependLine(this StringBuilder sb, string value)
{
sb.Insert(0, value + Environment.NewLine);
}
#endregion
}
}
그런 다음 다음을 추가하십시오.
using Application.Code.Helpers;
StringBuilder를 사용하려는 클래스의 맨 위에 그리고 StringBuilder 변수와 함께 인텔리 센스를 사용할 때마다 Prepend 및 PrependLine 메서드가 표시됩니다. Prepend를 사용할 때는 Appending보다 역순으로 Prepend를 사용해야합니다.
이것은 작동합니다.
aStringBuilder = "newText" + aStringBuilder;
string
하지만 type 값에 대해서는 작동하지 않습니다 StringBuilder
. @ScubaSteve의 답변이 잘 작동합니다.