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.