I have a string value that its length is 5000 + characters long , i want to split this into 76 characters long with a new line at the end of each 76 characters. how woudld i do this in c#?
-
What Aric said, but are you sure you want to split in the middle of a word? – Robert Harvey Jun 17 '09 at 22:39
-
Writing an email client? – Matthew Whited Jun 17 '09 at 22:46
-
Or are you working on a UUEncode? – Matthew Whited Jun 17 '09 at 22:47
-
I using base64 Encode and writeing it to an XML – MartGriff Jun 17 '09 at 22:52
-
Sounds like a pretty normal reason to do this – Matthew Whited Jun 17 '09 at 23:12
-
@Mart, isn't this a duplicate of your earlier question? http://stackoverflow.com/questions/1009620/linq-to-xml-base64-encoded – CoderDennis Jun 18 '09 at 00:24
13 Answers
If you're writing Base64 data, try writing
Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
This will insert a newline every 76 characters

- 868,454
- 176
- 1,908
- 1,964
-
I'll be damned, so it will. Should be fast too, uses unsafe code. ;) – Robert Harvey Jun 18 '09 at 00:35
-
pretty sure this is the winner becasue the others would have to run though this converter anyway – Matthew Whited Jun 18 '09 at 01:52
A little uglier ... but much faster ;) (this version took 161 ticks... Aric's took 413)
I posted my test code on my blog. http://hackersbasement.com/?p=134 (I also found StringBuilder to be much slower than string.Join)
http://hackersbasement.com/?p=139 <= updated results
string chopMe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Stopwatch sw = new Stopwatch();
sw.Start();
char[] chopMeArray = chopMe.ToCharArray();
int totalLength = chopMe.Length;
int partLength = 12;
int partCount = (totalLength / partLength) + ((totalLength % partLength == 0) ? 0 : 1);
int posIndex = 0;
char[] part = new char[partLength];
string[] parts = new string[partCount];
int get = partLength;
for (int i = 0; i < partCount; i++)
{
get = Math.Min(partLength, totalLength - posIndex);
Array.Copy(chopMeArray, posIndex, part, 0, get);
parts[i] = new string(part, 0, get);
posIndex += partLength;
}
var output = string.Join("\r\n", parts) + "\r\n";
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);

- 22,160
- 4
- 52
- 69
-
-
I've updated my answer - you might want to run your benchmark again ;) – Joel Coehoorn Jun 18 '09 at 00:20
-
-
I don't see it yet. Anyway, if I'm doing the benchmark correctly mine runs in about 40 ticks on average. – Joel Coehoorn Jun 18 '09 at 01:07
-
I updated my site again. (the ticks are the comments next to the Console.WriteLine()s) ... and Joel you are right I wasn't resetting the timer. This shows StringBuilder versions to be the fastest now. – Matthew Whited Jun 18 '09 at 01:15
-
I have tried to keep them all in line but i will change them back to methods shortly and run it again – Matthew Whited Jun 18 '09 at 01:16
-
Okay, you mean on the blog post you linked. I see it now. I don't think you really got the point of the code I posted. Note that I _never_ concatenate any strings. It's all copying from buffer to buffer, and I create the result by calling the string constructor directly. – Joel Coehoorn Jun 18 '09 at 01:36
-
Another suggestion: you really need two sets of benchmarks. One with a shorter string (say, 40 characters) and another with a very long string (say, 2000 characters). – Joel Coehoorn Jun 18 '09 at 01:39
-
Yeah I was trying to make that part similar for all of the tests to remove it from the picture. But I am working on a cleaner version that is pretty much a direct copy of each persons code shortly – Matthew Whited Jun 18 '09 at 02:04
-
-
what type of computer do you have? On my computer, taking what you have on your website and switching my old code with my new code from this thread I get: #1 39464, #2 48784, #341160, #4 45552, #5 8000, #6 1109656 (running inside visual studio, debugging mode) – Fredou Jun 18 '09 at 03:06
-
Windows Vista Ultimate, AMD Althon 64 X2 Dual Core 6000+ (3.0 GHz), 4GB RAM (Dual Core 64 bit) ... with a bunch of crap running at the same time – Matthew Whited Jun 18 '09 at 03:19
-
@Fredou: 1109656 is a _long_ time in computer terms. You're doing something wrong with the benchmarks. – Joel Coehoorn Jun 18 '09 at 03:26
-
@Joel, I have an Intel processor? maybe that is why... I just copy/pasted into VS and ran it – Fredou Jun 18 '09 at 03:34
-
@Matthew, again, I updated my answer and it's about 40% faster than the previous one on my computer. If you want to updated your bench on your website, go ahead. – Fredou Jun 18 '09 at 04:00
A side on this, if you want StringBuilder versus string performance the best article is the codeproject one found here.
(This doesn't show string size however)
In a nutshell, StringBuilder isn't faster until a threshold is met with the string length (or repeated contactenation), which you're well under, so stick the regular string concatenation and String methods.
Try this:
s = Regex.Replace(s, @"(?<=\G.{76})", "\r\n");
EDIT: Apparently, this is the slowest method of all those posted so far. I wonder how it does if you pre-compile the regex:
Regex rx0 = new Regex(@"(?<=\G.{76})");
s = rx0.Replace(s, "\r\n"); // only time this portion
Also, how does it compare to a straight matching approach?
Regex rx1 = new Regex(".{76}");
s = rx1.Replace(s, "$0\r\n"); // only time this portion
I've always wondered how expensive those unbounded lookbehinds are.

- 73,866
- 12
- 100
- 156
-
-
Alan, your first version wasn't as slow as I originally said. Joel pointed out I wasn’t resetting the timer. You can check you time on my blog post. And I will shortly be making a new post with everyone’s code refactored into methods. – Matthew Whited Jun 18 '09 at 01:40
-
Cool. But you've got a copy/paste error there: AlanM_3() is doing exactly the same thing as AlanM_1(). – Alan Moore Jun 18 '09 at 04:15
public static string InsertNewLine(string s, int len)
{
StringBuilder sb = new StringBuilder(s.Length + (int)(s.Length/len) + 1);
int start = 0;
for (start=0; start<s.Length-len; start+=len)
{
sb.Append(s.Substring(start, len));
sb.Append(Environment.NewLine);
}
sb.Append(s.Substring(start));
return sb.ToString();
}
where s would be your input string and len the desired line length (76).

- 94,805
- 45
- 217
- 260
-
+1 for being the canonical solution, and EXACTLY what was asked for. – Robert Harvey Jun 18 '09 at 00:28
-
The best way to use line breaks is using: Environment.NewLine, instead of "\n". – Zanoni Jun 18 '09 at 12:24
string[] FixedSplit(string s, int len)
{
List<string> output;
while (s.Length > len)
{
output.Add(s.Substring(0, len) + "\n");
s.Remove(0, len);
}
output.Add(s + "\n");
return output.ToArray();
}

- 8,002
- 1
- 34
- 48
-
...with the provision that if you wanted a single string back, you would have to spin through the returned array and mash all of the strings back together. – Robert Harvey Jun 17 '09 at 22:41
-
-
-
That should work too, but you don't need the \r\n's, as newlines have already been put in by Aric. – Robert Harvey Jun 17 '09 at 22:48
public static IEnumerable<string> SplitString(string s, int length)
{
var buf = new char[length];
using (var rdr = new StringReader(s))
{
int l;
l = rdr.ReadBlock(buf, 0, length);
while (l > 0)
{
yield return (new string(buf, 0, l)) + Environment.NewLine;
l = rdr.ReadBlock(buf, 0, length);
}
}
}
Then to put them back together:
string theString = GetLongString();
StringBuilder buf = new StringBuilder(theString.Length + theString.Length/76);
foreach (string s in SplitString(theString, 76) { buf.Append(s); }
string result = buf.ToString();
Or you could do this:
string InsertNewLines(string s, int interval)
{
char[] buf = new char[s.Length + (int)Math.Ceiling(s.Length / (double)interval)];
using (var rdr = new StringReader(s))
{
for (int i=0; i<buf.Length-interval; i++)
{
rdr.ReadBlock(buf, i, interval);
i+=interval;
buf[i] = '\n';
}
if (i < s.Length)
{
rdr.ReadBlock(buf, i, s.Length - i);
buf[buf.Length - 1] = '\n';
}
}
return new string(buf);
}

- 399,467
- 113
- 570
- 794
-
-
The main advantage is that this makes it easy to change the function to accept a plain stream. Then you could pass something like a file stream to it and maybe never load the entire string in memory initially in the first place. – Joel Coehoorn Jun 17 '09 at 23:46
-
Added a new method that put the result directly into a buffer - should be very fast. – Joel Coehoorn Jun 17 '09 at 23:55
-
@Joel, from Matthew post you said I had wrong ticks, you were right and I found out why: http://stackoverflow.com/questions/1017608/about-the-stopwatch-elapsedticks – Fredou Jun 19 '09 at 14:50
In the end, this would be what I would use, I think
static string fredou()
{
string s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
int partLength = 12;
int stringLength = s.Length;
StringBuilder n = new StringBuilder(stringLength + (int)(stringLength / partLength) + 1);
int chopSize = 0;
int pos = 0;
while (pos < stringLength)
{
chopSize = (pos + partLength) < stringLength ? partLength : stringLength - pos;
n.Append(s , pos, chopSize);
n.Append("\r\n");
pos += chopSize;
}
return n.ToString();
}
by looking at AppendLine under reflector:
<ComVisible(False)> _
Public Function AppendLine(ByVal value As String) As StringBuilder
Me.Append(value)
Return Me.Append(Environment.NewLine)
End Function
Public Shared ReadOnly Property NewLine As String
Get
Return ChrW(13) & ChrW(10)
End Get
End Property
For me, speed wise, doing it manually > AppendLine

- 19,848
- 10
- 58
- 113
-
1
-
-
The first for loop doesn't count for time in Fredou's solution, since it builds the test string. Is it still 270K ticks? I read the first for loop as 7000 new string initializations. – Robert Harvey Jun 18 '09 at 00:26
-
(I really don't think you want to do this the way you did... but we will see) – Matthew Whited Jun 18 '09 at 02:05
-
Use AppendLine() instead of calling Append() twice. Also becasue of the way .Net handles strings you will probably see a decrease in memory usage as well. I have to call it a night but feel free to post your results as a comment on my blog. – Matthew Whited Jun 18 '09 at 04:10
One more.... (first time through slowish, subsequent runs, similar to the faster times posted above)
private void button1_Click(object sender, EventArgs e)
{
string chopMe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Stopwatch sw = new Stopwatch();
sw.Start();
string result = string.Join("\r\n", ChopString(chopMe).ToArray());
sw.Stop();
MessageBox.Show(result + " " + sw.ToString());
}
public IEnumerable<string> ChopString(string s)
{
int i = 0;
while (i < s.Length)
{
yield return i + PARTLENGTH <= s.Length ? s.Substring(i,PARTLENGTH) :s.Substring(i) ;
i += PARTLENGTH;
}
}
Edit: I was curious to see how fast substring was...

- 18,465
- 9
- 55
- 92
-
You make a good point. for me next test I will loop them all twice. The way string work the first to parse would the the slowest. – Matthew Whited Jun 18 '09 at 01:58
The string is 5000 characters... I don't think speed is really of the essence unless you're doing this thousands or maybe even millions of times, especially when the OP didn't even mention speed being important. Premature optimization?
I would probably use recursion as it will, in my opinion, lead to the simplest code.
This may not be syntatically correct, as I know .NET but not C#.
String ChunkString(String s, Integer chunkLength) {
if (s.Length <= chunkLength) return s;
return String.Concat(s.Substring(0, chunkLength),
ChunkString(s.Substring(chunkLength)));
}

- 7,837
- 5
- 44
- 56
-
Yeah, we know that; we're only doing the benchmarking to satisfy our curiosity. – Alan Moore Jun 18 '09 at 04:22
mostly for the fun of it, here's a different solution implemented as extension method to string: (\r\n used explicitly so will only support that format for newline);
public static string Split(this string str, int len)
{
char org = str.ToCharArray();
int parts = str.Length / len + (str.Length % len == 0 ? 0 : 1);
int stepSize = len + newline.Length;
char[] result = new char[parts * stepSize];
int resLen = result.Length;
for (int i =0;i<resLen ;i+stepSize)
{
Array.Copy(org,i*len,result,i*stepSize);
resLen[i++] = '\r';
resLen[i++] = '\n';
}
return new string(result);
}

- 21,497
- 7
- 62
- 96
I'm spliting the string by 35
var tempstore ="12345678901234567890123456789012345";
for (int k = 0; k < tempstore.Length; k += 35)
{
PMSIMTRequest.Append(tempstore.Substring(k, tempstore.Length - k > 35 ? 35 : tempstore.Length - k));
PMSIMTRequest.Append(System.Environment.NewLine);
}
messagebox.Show(PMSIMTRequest.tostring());

- 8,198
- 71
- 51
- 66

- 53
- 1
- 6
@M4N's answer is very good , but I think while statement
is easier to understand than for statement
.
public static string InsertNewLine(string source, int len = 76)
{
var sb = new StringBuilder(source.Length + (int)(source.Length / len) + 1);
var start = 0;
while ((start + len) < source.Length)
{
sb.Append(source.Substring(start, len));
sb.Append(Environment.NewLine);
start += len;
}
sb.Append(source.Substring(start));
return sb.ToString();
}

- 170
- 2
- 10