Files
csvu/src/csv.zig
T
2024-08-22 09:48:04 +02:00

119 lines
3.0 KiB
Zig

const std = @import("std");
const CsvError = error{
NoDelimiterFound,
};
fn contains(arr: []const u8, target: u8) bool {
for (arr) |element| {
if (element == target) {
return true;
}
}
return false;
}
pub fn determineDelimiter(str: []const u8) !u8 {
const alloc = std.heap.page_allocator;
const possibleDelimiter = [_]u8{ ',', ';', '\t', '|' };
var countMap = std.AutoHashMap(u8, u32).init(alloc);
for (possibleDelimiter) |del| {
try countMap.put(del, 0);
}
for (str) |c| {
if (!contains(&possibleDelimiter, c)) {
continue;
}
const current = countMap.get(c) orelse 0;
try countMap.put(c, current + 1);
}
var currDel: u8 = ' ';
var highest: u32 = 0;
var iter = countMap.keyIterator();
while (iter.next()) |key| {
const val = countMap.get(key.*) orelse 0;
if (val > highest) {
currDel = key.*;
highest = val;
}
}
if (currDel == ' ') {
return CsvError.NoDelimiterFound;
}
return currDel;
}
const CsvFile = struct {
header: std.ArrayList([]const u8),
entries: std.ArrayList(std.ArrayList([]const u8)),
pub fn isValid(self: CsvFile) bool {
const colNum = self.header.items.len;
for (self.entries.items) |entry| {
if (entry.items.len != colNum) {
return false;
}
}
return true;
}
};
pub fn loadFile(filepath: []const u8) !CsvFile {
const alloc = std.heap.page_allocator;
var file = try std.fs.cwd().openFile(filepath, .{});
defer file.close();
var buf_reader = std.io.bufferedReader(file.reader());
var in_stream = buf_reader.reader();
var buffer: [4096]u8 = undefined;
var readHeader = false;
var headerList: std.ArrayList([]const u8) = undefined;
var entries = std.ArrayList(std.ArrayList([]const u8)).init(alloc);
var delimiter: u8 = ' ';
while (try in_stream.readUntilDelimiterOrEof(&buffer, '\n')) |line| {
if (delimiter == ' ') {
delimiter = try determineDelimiter(line);
}
const del = delimiter;
var entr = std.ArrayList([]const u8).init(alloc);
var splitIt = std.mem.splitSequence(u8, line, &[_]u8{del});
while (splitIt.next()) |part| {
_ = try entr.append(part);
}
if (!readHeader) {
headerList = entr;
readHeader = true;
continue;
}
_ = try entries.append(entr);
}
return CsvFile{ .entries = entries, .header = headerList };
}
test "Determine delimiter" {
const del = try determineDelimiter("this,is,a,test");
std.testing.expect(del == ',');
const del2 = try determineDelimiter("th#is; is,a; test; with,many;symbols");
std.testing.expect(del2 == ';');
determineDelimiter("This does not have an delimiter") catch |err| {
try std.testing.expect(err == CsvError.NoDelimiterFound);
};
}