As with my other posts to these questions...."It depends"...
There have certainly been some excellent suggestions for specific situations.
Recently I was working on a project that involved very complex manipulation of text (size ranging from 25K to 500K characters). This was in prepration for publication of the raw information.
After evaluating many of the techniques (StringBuilder, String.Format, String.Replace(), etc) we developed a solution where we used a linked list of "Segment Descriptors" which was a very simple class of the form below:
class SegmentDescriptor
{
int StringID;
int StartIndex;
int EndIndex;
}
Initially The content was:
{1, 0, 50000}
Removing a a portion of the content: (locations 100 thru 125)
{1, 0, 99}
{1, 126, 50000}
Inserting additional content 30 character string at offset 200
{1, 0, 99}
{1, 126, 200}
{2, 0, 29}
{1, 201, 50000}
etc...
The advantage of this approach was the the character data itself was rarely if ever "moved" in memory. Nor were additional copies made (potentially inducing significant GC).
After all of the work was done, the total file size was calculated and a StringBuilder initialized with the appropriate capacity, the individual segments were then appended into the StringBuilder, and the final string extracted [via ToString()]
For this particular application this provided significant performance improvements (in rare cases over an order of magnitude). The primary downside was that there was a fairly complex development process to create and validate the class library. Because this process was going to be run on thousands of documents on a regular basis, the amortized cost of the development compared to the improved response time of the application was a "win" situation.
TheCPUWizard is a trademark of Dynamic Concepts Development Corp. Please visit us at www.dynconcepts.com