// Zig 9.1
const std = @import("std");

const max_text_split_items: usize = 128;
const max_text_split_size: usize = 1024;

fn TextSplit(
    text: [*:0]const u8, // normal string
    count: *usize, // pointer to count
    textRow: *[max_text_split_items]usize, // pointer to slice of usize
) [max_text_split_items][*:0]const u8 {
    // these are static don't require allocation
    var result: [max_text_split_items][*:0]const u8 = undefined;
    var buffer: [max_text_split_size]u8 = .{0} ** max_text_split_size;
    var start: usize = 0;
    var end: usize = 0;
    var counter: usize = 0;
    if (textRow != undefined) textRow.*[0] = 0;
    while (true) {
        // copy [*:0]const u8 into [N]u8 so we can modify it and reference
        // it outside this function call.
        buffer[end] = text[end];
        switch (text[end]) {
            ';' => { // Replace ; with \0 bump counter and set pointer to slice range
                if (end - start > 0) {
                    buffer[end] = '\x00';
                    result[counter] = @ptrCast([*:0]const u8, buffer[start..end :0]);
                    counter += 1;
                    if (textRow != undefined)
                        textRow.*[counter] = textRow.*[counter - 1];
                    if (counter == max_text_split_items) break;
                }
                start = end + 1;
            },
            '\n' => { // same as ; but increment textRow
                if (end - start > 0) {
                    buffer[end] = '\x00';
                    result[counter] = @ptrCast([*:0]const u8, buffer[start..end :0]);
                    counter += 1;
                    if (textRow != undefined)
                        textRow.*[counter] = textRow.*[counter - 1] + 1;
                    if (counter == max_text_split_items) break;
                }
                start = end + 1;
            },
            '\x00' => { // set final string and break
                if (end - start > 0) {
                    result[counter] = @ptrCast([*:0]const u8, buffer[start..end :0]);
                    counter += 1;
                }
                break;
            },
            else => {},
        }
        // at any point if the input text is greater than max_text_split
        // size break
        if (end >= max_text_split_size) {
            break;
        }
        end += 1;
    }
    // set count to counter so we can interate over this slice of pointers
    count.* = counter;
    return result;
}

test "TextSplit - Hello World" {
    const input = "Hello;World";
    const outcome: [2][:0]const u8 = .{ "Hello", "World" };
    var count: usize = 0;
    const calc = TextSplit(input, &count, undefined);
    var c: usize = 0;
    while (c < count) {
        try std.testing.expectEqualStrings(std.mem.span(calc[c]), outcome[c]);
        c += 1;
    }
}

test "TextSplit - Using Undefined Row Test" {
    const input = "Hello\nCruel\nWorld";
    const row_outcome: [3]usize = .{ 0, 1, 2 };
    var count: usize = 0;
    var row: [max_text_split_items]usize = undefined;
    _ = TextSplit(input, &count, &row);
    var c: usize = 0;
    while (c < count) {
        try std.testing.expectEqual(row_outcome[c], row[c]);
        c += 1;
    }
}

test "TextSplit - Reusing Static Locals Test" {
    const input = "Hello;Cruel;World;;;";
    const outcome: [3][:0]const u8 = .{ "Hello", "Cruel", "World" };
    var count: usize = 0;
    const calc = TextSplit(input, &count, undefined);
    var c: usize = 0;
    while (c < count) {
        try std.testing.expectEqualStrings(std.mem.span(calc[c]), outcome[c]);
        c += 1;
    }
    const input2 = "Beep\nBop";
    const outcome2: [2][:0]const u8 = .{ "Beep", "Bop" };
    var count2: usize = 0;
    var rows2: [max_text_split_items]usize = .{0} ** max_text_split_items;
    const calc2 = TextSplit(input2, &count2, &rows2);
    c = 0;
    while (c < count2) {
        try std.testing.expectEqualStrings(std.mem.span(calc2[c]), outcome2[c]);
        c += 1;
    }
}

Generated by AlexJGriffith using scpaste at Sun Sep 25 04:57:18 2022. EDT. (original)