Table of Contents

Non-Alloc String Splitter for .NET / Unity

Runtime/Text/NonAllocStringSplitter.cs   HeaderDoc

(c) 2024 Sator Imaging, Licensed under the MIT License https://github.com/sator-imaging/Unity-Fundamentals

How to Use

var result = new NonAllocStringSplitter("A,,B,C,", ',');  // 3 items. empty will be removed

// split by sequence or by any char. using extension method
result = "A, B, C".AsSpan().SplitNonAlloc(" ,");     // 1 item. no ' ,' sequence found
result = "A, B, C".AsSpan().SplitAnyNonAlloc(" ,");  // 3 items. split by ' ' or ','

// enumerate
for (int i = 0; i < result.Count; i++)
{
    var span = result[i];
}

foreach (var span in result)
{
    Console.WriteLine(span.ToString());
}

// can pass 'stackalloc char[]' directly
result = "A, B, C".AsSpan().SplitNonAlloc(stackalloc char[] { ' ', ',' });

Incremental String Splitter

Allocation-free incremental splitter processes only when consuming enumerator so it supports unlimited length of input text and any number of items can be splitted. (inspired by .NET 9 preview feature)

var span = "ABC DEF".AsSpan();

foreach (var range in span.SplitEnumerator(' '))
{
    // use Range struct from enumerator to extract result
    Console.WriteLine(span[range].ToString());
}

TrySplit Extensions

Designed to split input text into 2 items.

var span = "https://www.inter.net/path/to/file.html?opt=value&other=data#anchor";

// TrySplitLast searches splitter from end of text
if (!span.TrySplitLast('#', out var urlAndOptions, out var anchorSpan))
{
    urlAndOptions = span;
    anchorSpan = default;
}

Span<Range> optionNameRanges = default;
Span<Range> optionValueRanges = default;

if (urlAndOptions.TrySplit('?', out var url, out var allOptions)
{
    optionNameRanges = stackalloc Range[16];
    optionValueRanges = stackalloc Range[16];

    int i = -1;
    foreach (var range in allOptions.SplitEnumerator('&'))
    {
        i++;

        if (!allOptions[range].TrySplit('=', out var name, out var value)
        {
            name = allOptions[range];
            value = string.Empty;
        }

        optionNameRanges[i] = new(range.Start, range.Start + name.Length);
        optionValueRanges[i] = new(range.End - value.Length, range.End);
    }
}