Here is mine

- 0 allocations

- configurable

- let's you use it how you wish

- fast


```D
import std;
void main()
{
    string a = "abc;def;ab";
    writeln("a => ", a);

    foreach(item; split(a, ';'))
        writeln("\t", item);


    string b = "abc;    def   ;ab";
    writeln("a => ", b);

    foreach(item; split(b, ';', SplitOption.TRIM))
        writeln("\t", item);


    string c= "abc;    ;       ;def   ;ab";
    writeln("a => ",c);

foreach(item; split(c, ';', SplitOption.TRIM | SplitOption.REMOVE_EMPTY))
        writeln("\t", item);
}

SplitIterator!T split(T)(const(T)[] buffer, const(T) delimiter, SplitOption option = SplitOption.NONE)
{
    return SplitIterator!T(buffer, delimiter, option);
}

struct SplitIterator(T)
{
    const(T)[] buffer;
    const(T) delimiter;
    SplitOption option;
    int index = 0;

        int count()
        {
                int c = 0;
                foreach(line; this)
                {
                        c++;
                }
                index = 0;
                return c;
        }

        const(T) get(int index)
        {
                return buffer[index];
        }
        
    int opApply(scope int delegate(const(T)[]) dg)
    {
        auto length = buffer.length;
        for (int i = 0; i < length; i++)
        {
            if (buffer[i] == '\0')
            {
                length = i;
                break;
            }
        }

        int result = 0;
        for (int i = index; i < length; i++)
        {
            int entry(int start, int end)
            {
                // trim only if we got something
if ((end - start > 0) && (option & SplitOption.TRIM))
                {
                    for (int j = start; j < end; j++)
                        if (buffer[j] == ' ')
                            start += 1;
                        else
                            break;
                    for (int k = end; k >= start; k--)
                        if (buffer[k - 1] == ' ')
                            end -= 1;
                        else
                            break;
                                        
                                        // nothing left
                                        if(start >= end) return 0;
                }

//printf("%i to %i :: %i :: total: %lu\n", start, end, index, buffer.length);
                return dg(buffer[start .. end]) != 0;
            }

            auto c = buffer[i];
            if (c == delimiter)
            {
if (i == index && (option & SplitOption.REMOVE_EMPTY))
                {
                    // skip if we keep finding the delimiter
                    index = i + 1;
                    continue;
                }

                if ((result = entry(index, i)) != 0)
                    break;

                // skip delimiter for next result
                index = i + 1;
            }

            // handle what's left
            if ((i + 1) == length)
            {
                result = entry(index, i + 1);
            }
        }
        return result;
    }

        // copy from above, only replace if above has changed
    int opApply(scope int delegate(int, const(T)[]) dg)
    {
        auto length = buffer.length;
        for (int i = 0; i < length; i++)
        {
            if (buffer[i] == '\0')
            {
                length = i;
                break;
            }
        }

                int n = 0;
        int result = 0;
        for (int i = index; i < length; i++)
        {
            int entry(int start, int end)
            {
                // trim only if we got something
if ((end - start > 0) && (option & SplitOption.TRIM))
                {
                    for (int j = start; j < end; j++)
                        if (buffer[j] == ' ')
                            start += 1;
                        else
                            break;
                    for (int k = end; k >= start; k--)
                        if (buffer[k - 1] == ' ')
                            end -= 1;
                        else
                            break;
                                        
                                        // nothing left
                                        if(start >= end) return 0;
                }

//printf("%i to %i :: %i :: total: %lu\n", start, end, index, buffer.length);
                return dg(n++, buffer[start .. end]) != 0;
            }

            auto c = buffer[i];
            if (c == delimiter)
            {
if (i == index && (option & SplitOption.REMOVE_EMPTY))
                {
                    // skip if we keep finding the delimiter
                    index = i + 1;
                    continue;
                }

                if ((result = entry(index, i)) != 0)
                    break;

                // skip delimiter for next result
                index = i + 1;
            }

            // handle what's left
            if ((i + 1) == length)
            {
                result = entry(index, i + 1);
            }
        }
        return result;
    }
}


enum SplitOption
{
    NONE = 0,
    REMOVE_EMPTY = 1,
    TRIM = 2
}

```

Reply via email to