Most of these answers work, but they run into problems when dealing with emoji support. As these character may appear as one such as 👨👩👧👦, but under the hood they are actually: 👨+👩+👧+👦, if we were to split incorrectly, the emoji might end up broken up.
I wrote up a quick set of tests as this:
[InlineData(null, 1, "")]
[InlineData(null, 2, "")]
[InlineData(" ", 3, "")]
[InlineData("aaaaa", 1, "a a a a a")]
[InlineData("aaaaa", 2, "aa aa a")]
[InlineData("aaaaa", 3, "aaa aa")]
[InlineData("aaaaa", 4, "aaaa a")]
[InlineData("aaaaa", 6, "aaaaa")]
[InlineData("aaaaa", 30, "aaaaa")]
[InlineData("🌓🌓🌓🌓🌓", 4, "🌓🌓🌓🌓 🌓")]
[InlineData("🌓🌓a🌓🌓", 4, "🌓🌓a🌓 🌓")]
[InlineData("aaa🌓🌓", 4, "aaa🌓 🌓")]
[InlineData("aaa👨👩👧👦🌓", 4, "aaa👨👩👧👦 🌓")]
public void TestAddSpaces(string? value, int numOfCharsBetweenSpaces, string expected)
{
...Add Space Code Here
Assert.Equal(expected, actual);
}
Doing just a insert of a space of every X characters based on string.length ended with results like as the emoji was split in the middle:
Assert.Equal() Failure
↓ (pos 4)
Expected: aaa🌓 🌓
Actual: aaa� �🌓
↑ (pos 4)
Assert.Equal() Failure
↓ (pos 4)
Expected: aaa👨👩👧👦 🌓
Actual: aaa� �👩 👧 👦🌓
Using the .Net 5+ answer from this Stack Overflow question: How can I split a Unicode string into multiple Unicode characters in C#? on splitting up the string elements we're able to reliable get spacing inserted in the string in a manner that a user would be expecting.
public static string AddSpacesSplitText(this string? value, int numOfCharsBetweenSpaces)
{
if (string.IsNullOrWhiteSpace(value))
return string.Empty;
var elements = SplitIntoTextElements(value);
string retval = string.Empty;
for (int i = 0; i <= elements.Length; i += numOfCharsBetweenSpaces)
{
retval += string.Join(string.Empty, elements.Skip(i).Take(numOfCharsBetweenSpaces)) + " ";
}
return retval.Trim();
}
public static string[] SplitIntoTextElements(string input)
{
IEnumerable<string> Helper()
{
for (var en = StringInfo.GetTextElementEnumerator(input); en.MoveNext();)
yield return en.GetTextElement();
}
return Helper().ToArray();
}
Now running my test cases
[Theory]
[InlineData(null, 1, "")]
[InlineData(null, 2, "")]
[InlineData(" ", 3, "")]
[InlineData("aaaaa", 1, "a a a a a")]
[InlineData("aaaaa", 2, "aa aa a")]
[InlineData("aaaaa", 3, "aaa aa")]
[InlineData("aaaaa", 4, "aaaa a")]
[InlineData("aaaaa", 6, "aaaaa")]
[InlineData("aaaaa", 30, "aaaaa")]
[InlineData("🌓🌓🌓🌓🌓", 4, "🌓🌓🌓🌓 🌓")]
[InlineData("🌓🌓a🌓🌓", 4, "🌓🌓a🌓 🌓")]
[InlineData("aaa🌓🌓", 4, "aaa🌓 🌓")]
[InlineData("aaa👨👩👧👦🌓", 4, "aaa👨👩👧👦 🌓")]
public void TestAddSpacesSplitText(string? value, int numOfCharsBetweenSpaces, string expected)
{
var actual = value.AddSpacesSplitText(numOfCharsBetweenSpaces);
Assert.Equal(expected, actual);
}
They all now pass as expected.