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);
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 two string like below
var str1 = '20180215.20150215.3.1.0.0';
var str2 = '20180215.3.1.0.0';
I need to get the last four word after splitting these string with .
var str1Arr = str1.split('.')
What i need is a generic method to get last four words 3.1.0.0.
Thanks
var lastFour = str1Arr.Reverse().Take(4).Reverse().ToArray();
public static class SplitExtension
{
public static string LastNItems(this string str, int nItem, char separator = '.')
{
return string.Join(separator.ToString(), str.Split(separator).Reverse().Take(nItem).Reverse());
}
public static string[] LastNItems(this string[] strArray, int nItem)
{
return strArray.Reverse().Take(nItem).Reverse().ToArray();
}
}
This will enable you to do
var str1 = "20180215.20150215.3.1.0.0";
var str1Last4 = str1.LastNItems(4); // "3.1.0.0"
var str1Last4Items = str1.Split('.').LastNItems(4); // ["3","1","0","0"]
or for completion
var str1Last4Items = str1.LastNItems(4).Split('.'); // ["3","1","0","0"]
You can use it by extension methods.
public static class CommonExtension
{
public static List<string> LastNItem(this string str, int nItem, string separator = ".")
{
var splittedWords = str.Split(new [] { separator }, StringSplitOptions.None);
var res = splittedWords.Reverse().Take(nItem).Reverse().ToList();
return res;
}
}
Then you can call it everywhere you want.
var str1 = "1.0.0";
var str2 = "20180215.3.1.0.0";
var str1Last4 = str1.LastNItem(4);
var str2Last4 = str2.LastNItem(4);
Why not just Skip top Length - 4 items?
string str1 = "20180215.20150215.3.1.0.0";
string[] str1Arr = str1.Split('.');
var result = str1Arr
.Skip(str1Arr.Length - 4)
.ToArray(); // if you want an array materialization
This code will do even when str1Arr.Length < 4 (in this case the entire str1Arr copy will be returned). In case you want a string as the result you can just try Substring (without creating any arrays)
string str1 = "20180215.20150215.3.1.0.0";
string result = str1;
int index = result.Length;
for (int i = 0; i < 4; ++i) {
index = str1.LastIndexOf('.', index - 1);
if (index < 0)
break;
}
result = index < 0 ? result : result.Substring(index + 1);
public static string GetLastFour(string str)
{
string[] arr = str.Split('.');
System.Text.StringBuilder lastFour = new System.Text.StringBuilder();
if (arr.Length >= 4)
{
for (int k = arr.Length - 4; k < arr.Length; k++)
{
if (k == arr.Length - 1)
{
lastFour.Append(arr[k]);
}
else
{
lastFour.Append(arr[k] + ".");
}
}
}
return lastFour.ToString();
}
This would be faster than double reverse answer.
var str1 = "20180215.20150215.3.1.0.0";
var str2 = "20180215.3.1.0.0";
var words = str1.Split('.');
var toSkip = words.Length - 4;
var result = string.Join(".", words.Skip(toSkip));
A bit of testing showed that is is just slightly faster than double reverse.
What is 10 times faster than this one?
Well avoiding memory allocations and enumerations will be.
Here are the results of comparing 3 different extension methods for 10M iterations:
double reverse: 6463ms
split + skip: 5269ms
straight: 492ms
void Main()
{
var str1 = "20180215.20150215.3.1.0.0";
var numIterations = 10000000;
var timer = new Stopwatch();
timer.Start();
for (var i = 0; i < numIterations; i++)
{
str1.LastNItemsDoubleReverse(4);
}
timer.Stop();
timer.ElapsedMilliseconds.Dump("double reverse");
timer.Reset();
timer.Start();
for (var i = 0; i < numIterations; i++)
{
str1.LastNItemsSplitNSkip(4);
}
timer.Stop();
timer.ElapsedMilliseconds.Dump("split + skip");
timer.Reset();
timer.Start();
for (var i = 0; i < numIterations; i++)
{
str1.LastNItemsStraight(4);
}
timer.Stop();
timer.ElapsedMilliseconds.Dump("straight");
}
public static class ext
{
public static string LastNItemsDoubleReverse(this string str, int nItem, char separator = '.')
{
return string.Join(separator.ToString(), str.Split(separator).Reverse().Take(nItem).Reverse());
}
public static string LastNItemsSplitNSkip(this string str, int nItem, char separator = '.')
{
var words = str.Split(separator);
var toSkip = words.Length - nItem;
return string.Join($"{separator}", words.Skip(toSkip));
}
public static string LastNItemsStraight(this string str, int nItem, char separator = '.')
{
int j=1,i=str.Length-1;
for (;i>=0 && j<nItem;i--){
if(str[i]==separator) j++;
}
return str.Substring(i);
}
}
Try the following :
List<string> GetLastFourWords()
{
List<string> lastFour = new List<string>();
try
{
string[] arr = str1.split('.');
for(int i = 3; i >= 0; i-- )
{
lastFour.Add(arr[str1.length - 1 - i]);
}
}
catch(Exception ex)
{
}
return lastFour;
}
i searched for a method to split strings and i found one.
Now my problem is that i canĀ“t use the method like it is described.
Stackoverflow answer
It is going to tell that i
cannot implicitly convert type
'System.Collections.Generic.IEnumerable' to 'string[]'.
The provided method is:
public static class EnumerableEx
{
public static IEnumerable<string> SplitBy(this string str, int chunkLength)
{
if (String.IsNullOrEmpty(str)) throw new ArgumentException();
if (chunkLength < 1) throw new ArgumentException();
for (int i = 0; i < str.Length; i += chunkLength)
{
if (chunkLength + i > str.Length)
chunkLength = str.Length - i;
yield return str.Substring(i, chunkLength);
}
}
}
How he said it is used:
string[] result = "bobjoecat".SplitBy(3); // [bob, joe, cat]
You have to use ToArray() method:
string[] result = "bobjoecat".SplitBy(3).ToArray(); // [bob, joe, cat]
You can implicitly convert Array to IEnumerable but cannot do it vice versa.
Note that you could even modify directly the method to return a string[]:
public static class EnumerableEx
{
public static string[] SplitByToArray(this string str, int chunkLength)
{
if (String.IsNullOrEmpty(str)) throw new ArgumentException();
if (chunkLength < 1) throw new ArgumentException();
var arr = new string[(str.Length + chunkLength - 1) / chunkLength];
for (int i = 0, j = 0; i < str.Length; i += chunkLength, j++)
{
if (chunkLength + i > str.Length)
chunkLength = str.Length - i;
arr[j] = str.Substring(i, chunkLength);
}
return arr;
}
}
If somehow you end up with this:
IEnumerable<string> things = new[] { "bob", "joe", "cat" };
you can transform it into string[] like this:
string[] myStringArray = things.Select(it => it).ToArray();
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 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();
}