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#?
If you're writing Base64 data, try writing
Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
This will insert a newline every 76 characters
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.
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);
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).
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();
}
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);
}
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...
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)));
}
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);
}
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
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());
#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();
}
Related
I am using the following function to split a string into chunks
public static IList<string> SplitChunks(string text, int chunkSize)
{
List<string> chunks = new List<string>();
int offset = 0;
while (offset < text.Length)
{
int size = Math.Min(chunkSize, text.Length - offset);
chunks.Add(text.Substring(offset, size));
offset += size;
}
return chunks;
}
Works fine but the issue is in many cases the chunk ends with an incomplete word such as
Input:
String: Hello Everyone. How are you?
Size: 10
Output:
Hello Ever
where I want it to return a full last word such as Hello Everyone
How can I modify my function so the last word is a full word regardless of the size of the chunk
You could split the string into words and then try to generate chunks of at least chunkSize size:
public static IList<string> SplitChunks(string text, int chunkSize)
{
var words = text.Split(' ');
var result = new List<string>();
int length = 0;
string current = "";
foreach(var word in words)
{
current += word + " ";
length += word.Length + 1;
if (length > chunkSize) {
result.Add(current);
current = "";
length = 0;
}
}
if (current != "")
result.Add(current);
return result;
}
You could do something like this, but it's a bit ugly because it's producing a side effect in the TakeWhile:
int count = 0;
const string text = "Hello Everyone. How are you?";
var ret = text.TakeWhile(s =>
{
var keepTaking = count < max;
count += s.Length + 1; // +1 for the space between words
return keepTaking;
});
Try this one too:
public static IList<string> SplitChunks(string text, int chunkSize)
{
var parts = text.Split(' ');
return parts.Skip(1).Aggregate(parts.Take(1).ToList(), (a, x) =>
{
if ((a.Last() + x).Length > chunkSize)
a.Add(x);
else
a[a.Count - 1] += " " + x;
return a;
});
}
When I call SplitChunks("Hello Everyone. How are you?", 10) I get this:
Hello
Everyone.
How are
you?
I have an string with var length for example "0009000A000B000C" and I want to split it at every 4 charter or every second charter, the result value I want to put-it in a new string.
var str1= 0009;
var str2= 000A;
var str3= 000B;
var str4= 000C;
I have try this code:
var str = "0009000A000B000C";
var splitgroup2 = ChunksUpto(str , 4);
static IEnumerable<string> ChunksUpto(string str, int maxChunkSize)
{
for (var i = 0; i < str.Length; i += maxChunkSize)
yield return str.Substring(i, Math.Min(maxChunkSize, str.Length - i));
}
but I don't know how to put the returned value in different string
Whit the new string value I want to do this kind:
dataGrid2.Rows.Add(modbusadd_dec, poiterlangrow1_dec, poiterlangrow2_dec, opt_dec, rangemin_dec + "-" + rangemax_dec, Nunit_dec, Nperfix_dec, Dunit_dec, Dprefix_dec, grouptype, splitgroup2);
var str = "0009000A000B000C";
var splitgroup2 = ChunksUpto(str , 4);
public string[] ChunksUpTo(string str, int count)
{
if(count == 0)
return null;
List<string> result = new List<string>();
int chunkCount = str.Length / count;
for(int i = 0; i < temp; i++)
result.Add(new string(str.Take(count).ToArray()))
return result.ToArray();
}
I did not test this code, but it should look like this,
you can take this code, enhance it and fix the bugs (if exits)
You can create method for this :
static string[] SplitInto(string value, int startIndex, int length)
{
List<string> result = new List<string>();
for(; startIndex + length < value.Length; startIndex += length)
result.Add(valuel.Substring(startIndex, length));
return result.ToArray();
}
And use it like :
string[] str = SplitInto("0009000A000B000C", 0, 3);
StringBuilder does not appear to have a Substring(start, len) method... what am I missing here?
The StringBuilder class has a special version of the ToString method that takes two arguments, exactly as Substring(startIndex, length).
StringBuilder sb = new StringBuilder("This is a Test");
string test = sb.ToString(10, 4);
Console.WriteLine(test); // result = Test
these are all ways you can get the desired substring:
StringBuilder b = new StringBuilder();
b.Append("some text to test out!");
string s = b.ToString(0, 6);
//or ....
char[] letters = new char[6];
b.CopyTo(0, letters, 0, 6);
string s1 = new string(letters);
//or
string s2 = null;
for (int i = 0; i < 6; i++)
{
s2 += b[i];
}
Another approach, if you dont want to build whole string (StringBuilder.ToString()) and get the substring:
public static StringBuilder SubString(this StringBuilder input, int index, int length)
{
StringBuilder subString = new StringBuilder();
if (index + length - 1 >= input.Length || index < 0)
{
throw new ArgumentOutOfRangeException("Index out of range!");
}
int endIndex = index + length;
for (int i = index; i < endIndex; i++)
{
subString.Append(input[i]);
}
return subString;
}
I have made this code to get from 2a3b to aabbb. This also has to apply when no numbers are given. Like aa2b => aabb.
The program is fully working but my problem is, it takes in alot of space. I think it is my split but my array will be like this if the input is 2a2b:
2
NULL
NULL
a
2
NULL
NULL
b
Does someone know what i'm doing wrong? Is it my split?
static void Main(string[] args)
{
string test = "";
int intNumber = 1;
string value = "2a2b";
string[] array = new string[20];
int count = 1;
array = Regex.Split(value, "(\\d{0,2})");
while (count < array.Length)
{
int num;
if (array[count] != "")
{
bool isNumeric = int.TryParse(array[count], out num);
if (!isNumeric)
{
test = test + string.fill(array[count], intNumber);
test = test + array[count];
Console.WriteLine(test);
intNumber = 1;
}
else
{
intNumber = num;
}
}
count++;
}
Console.WriteLine("woord:" + test);
Console.ReadLine();
How about using a simple Regex.Replace?
string input = "2a3bcccc";
string output = Regex.Replace(
input,
#"(\d+)(\w)",
m => new String(m.Groups[2].Value[0],int.Parse(m.Groups[1].Value)));
result : aabbbcccc
A simpler way to resolve your problem is to get rid of regex, the array creation would be like:
char[] array = value.ToArray();
The code, with the minor corrections due to the array and some improvements being a char array (intead of a string array):
static void Main(string[] args)
{
string test = "";
int intNumber = 1;
string value = "2a2b";
foreach (char c in value.ToArray())
{
int num;
bool isNumeric = int.TryParse(c.ToString(), out num);
if (!isNumeric)
{
test = test + new string(c, intNumber);
Console.WriteLine(test);
intNumber = 1;
}
else
{
intNumber = num;
}
}
Console.WriteLine("woord:" + test);
Console.ReadLine();
}
Quick test program works like a charm without using a regex.
const string value = "aa2b";
var result = "";
for (var i = 0; i < value.Length; i++)
{
int num;
if (Int32.TryParse(value.Substring(i, 1), out num))
{
for (var j = 0; j < num; j++)
{
result += value.Substring(i + 1, 1);
}
i++;
}
else
{
result += value.Substring(i, 1);
}
}
textBox1.AppendText("woord:" + result);
I generally try to avoid Regex, unless there is a complex pattern I need to verify.
Here is my solution to your problem:
string k = Console.ReadLine();
string t = "";
int count = 0, next;
for (int i = 0; i < k.Length; i++)
{
while (int.TryParse(k[i].ToString(), out next)) // Find the count of the next letter
{
count = count * 10 + next; // If count had a 2, and the next character is 3 (means we need to calculate 23), simply multiply the previous count by 10, and add the new digit
i++; // Move to the next character
}
t += new String(k[i], count > 0 ? count : 1); // Add the new sequence of letters to our string
count = 0; // Clear the current count
}
Console.WriteLine(t);
You can optimize the above, by using the StringBuilder class, but I think it's enough to understand the general solution first, rather than trying to find optimizations.
Let's say you have the string "This is a test"
I pass it to method zee, like ("This is a test", 1)
and want "test This is a";
I pass it to method zee, like ("This is a test", 2)
and want "a test This is";
the number can exceed the total words in variable. If it does it should loop around.
I started with....
public static string zee(string origString, int i)
{
StringBuilder sb = new StringBuilder();
ArrayList list = new ArrayList();
list.AddRange(origString.Split(' '));
// not sure here -
for (int c = i; c < (list.Count + i); c++)
{
sb.AppendFormat("{0} ", list[c]);
}
return sb.ToString();
}
for(int j=0; j < list.length; j++){
int idx = (j + i) % list.length;
sb.AppendFormat("{0} " , list[idx]);
}
Mostly like Brent Arias's solution, but I think a for loop is more readable, less likely to go infinite.
public static string zee(string origString, int i)
{
StringBuilder sb = new StringBuilder();
List<string> list = new List<string>();
list.AddRange(origString.Split(' '));
for (int j = 0; j < list.Count; j++)
{
int idx = (j + i) % list.Count;
sb.AppendFormat("{0} ", list[idx]);
}
return sb.ToString();
}
This is how I'd solve it.
private static string f(string s, int start)
{
var arr=s.Split(' ');
start %= arr.Length;
var res=arr.Skip(arr.Length - start).ToList();
res.AddRange(arr.Take(arr.Length - start));
return string.Join(" ", res);
}
I tried writing a one liner with linq but I don't see how to combine 2 lists. Union and Join aren't what I need.
This is how I'd solve it using strings.
public static string zee(string origString, int i)
{
string[] splitStr = origString.Split(' ');
string newStr = "";
// Not sure what you meant by wrap around but this should
// do the trick.
i %= splitStr.Length;
for (int j = (splitStr.Length - i); j < splitStr.Length; j++)
newStr += splitStr[j] + " "; // Add spaces taken by split :(
for (int j = 0; j < (splitStr.Length - i); j++)
newStr += splitStr[j] + " ";
return
newStr;
}
Here's an abomination trying to cram as much into one line as possible:
static string zee(string sentence, int wordCount)
{
var words = sentence.Split(' ');
return string.Join(" ", new[] { words.Skip(words.Count() - wordCount), words.Take(words.Count() - wordCount) }.SelectMany(w => w).ToArray());
}
I havn't tried it, but I think this would do it:
i %= list.Length;
int index = i;
do {
index %= list.Length;
sb.AppendFormat("{0} ", list[index]);
while (++index != i);
static string rearrange(string phase,int index)
{
string[] words = phase.Split(' ');
string[] newwords = new string[words.Length];
int pointer = index;
for (int i = 0; i < words.Length;i++ )
{
if(pointer>=words.Length)
{
pointer = 0;
}
newwords[i] = words[pointer];
pointer++;
}
return string.Join(" ", newwords);
}
Sounds like a homework question to me, but here is an efficient use of the .Net framework:
private static string [] SplitWords(string s, int startWord)
{
string[] words = s.Split(' ');
List<string> output = new List<string>();
output.AddRange(words.Skip(startWord).ToArray());
output.AddRange(words.Take(startWord).ToArray());
return output.ToArray();
}
There is absolutely no error checking in this function so you will have to modify it for production code but you get the idea.
public string SetStart(int startAt)
{
const string sentence = "this is a test so it is";
var words = sentence.Split(' ');
var x = (startAt > words.Count()) ? startAt%words.Count() : startAt;
return string.Join(" ", words.Skip(x).Concat(words.Take(x)));
}