In an attempt to summarize the question and all the good answers to this question, I decided to try to write a pair of string extensions that could
- split a string in respect to number of slices
- split a string in respect to number of text elements in each slice.
The effort resulted in the code below.
public static class Extensions
{
public static IEnumerable<string> SliceByNumber(this string value, int sliceCount, bool strict = false)
{
if (value == null) throw new ArgumentNullException(nameof(value));
if (sliceCount <= 0) throw new ArgumentException("Number of slices is invalid.", nameof(sliceCount));
StringInfo stringInfo = new StringInfo(value);
return stringInfo.Slice(stringInfo.LengthInTextElements / sliceCount, sliceCount, strict);
}
public static IEnumerable<string> SliceBySize(this string value, int sliceSize, bool strict = false)
{
if (value == null) throw new ArgumentNullException(nameof(value));
if (sliceSize <= 0) throw new ArgumentException("The size of the slices is invalid.", nameof(sliceSize));
StringInfo stringInfo = new StringInfo(value);
return stringInfo.Slice(sliceSize, stringInfo.LengthInTextElements / sliceSize, strict);
}
private static IEnumerable<string> Slice(this StringInfo stringInfo, int sliceSize, int sliceCount, bool strict)
{
stringInfo.CheckSliceValidity(sliceSize, sliceCount, strict);
int sliceStart = 0;
for (; sliceStart < (sliceCount - 1) * sliceSize; sliceStart += sliceSize)
{
yield return stringInfo.SubstringByTextElements(sliceStart, sliceSize);
}
yield return stringInfo.SubstringByTextElements(sliceStart);
}
private static void CheckSliceValidity(this StringInfo stringInfo, int sliceSize, int sliceCount, bool strict)
{
if (stringInfo.LengthInTextElements < sliceSize)
throw new ArgumentOutOfRangeException(nameof(sliceSize), "Number of elements in a slice is greather than the number of characters in the string value.");
if (stringInfo.LengthInTextElements < sliceCount)
throw new ArgumentOutOfRangeException(nameof(sliceSize), "Number of slices is greather than the number of characters in the string value.");
if (strict && sliceSize * sliceCount != stringInfo.LengthInTextElements)
throw new ArgumentException("Unable to slice the string into a number of strings of equal length.", nameof(sliceSize));
// Maybe other precautions?
}
}
static void SliceTest()
{
int slicesOrSize= 5;
string data = "OnceUponATime";
foreach (string slice in data.SliceByNumber(slicesOrSize, false))
{
Console.WriteLine(slice);
}
Console.WriteLine();
foreach (string slice in data.SliceBySize(slicesOrSize, false))
{
Console.WriteLine(slice);
}
}
Any comments or improvements are welcome.