classification.zig to use srf parser
This commit is contained in:
parent
9819c93cfe
commit
d6a104d2d5
1 changed files with 32 additions and 21 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
/// symbol::02315N600,asset_class::International Developed,pct:num:20
|
/// symbol::02315N600,asset_class::International Developed,pct:num:20
|
||||||
/// symbol::02315N600,asset_class::Bonds,pct:num:15
|
/// symbol::02315N600,asset_class::Bonds,pct:num:15
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const srf = @import("srf");
|
||||||
|
|
||||||
/// A single classification entry for a symbol.
|
/// A single classification entry for a symbol.
|
||||||
pub const ClassificationEntry = struct {
|
pub const ClassificationEntry = struct {
|
||||||
|
|
@ -41,7 +42,7 @@ pub const ClassificationMap = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parse a metadata SRF file into a ClassificationMap.
|
/// Parse a metadata SRF file into a ClassificationMap.
|
||||||
/// Each line is: symbol::<SYM>,sector::<S>,geo::<G>,asset_class::<A>,pct:num:<P>
|
/// Each record has: symbol::<SYM>,sector::<S>,geo::<G>,asset_class::<A>,pct:num:<P>
|
||||||
/// All fields except symbol are optional. pct defaults to 100.
|
/// All fields except symbol are optional. pct defaults to 100.
|
||||||
pub fn parseClassificationFile(allocator: std.mem.Allocator, data: []const u8) !ClassificationMap {
|
pub fn parseClassificationFile(allocator: std.mem.Allocator, data: []const u8) !ClassificationMap {
|
||||||
var entries = std.ArrayList(ClassificationEntry).empty;
|
var entries = std.ArrayList(ClassificationEntry).empty;
|
||||||
|
|
@ -55,36 +56,32 @@ pub fn parseClassificationFile(allocator: std.mem.Allocator, data: []const u8) !
|
||||||
entries.deinit(allocator);
|
entries.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
var line_iter = std.mem.splitScalar(u8, data, '\n');
|
var reader = std.Io.Reader.fixed(data);
|
||||||
while (line_iter.next()) |line| {
|
const parsed = srf.parse(&reader, allocator, .{ .alloc_strings = false }) catch return error.InvalidData;
|
||||||
const trimmed = std.mem.trim(u8, line, &std.ascii.whitespace);
|
defer parsed.deinit();
|
||||||
if (trimmed.len == 0 or trimmed[0] == '#') continue;
|
|
||||||
if (std.mem.startsWith(u8, trimmed, "#!")) continue;
|
|
||||||
|
|
||||||
// Parse comma-separated key::value pairs
|
for (parsed.records.items) |record| {
|
||||||
var symbol: ?[]const u8 = null;
|
var symbol: ?[]const u8 = null;
|
||||||
var sector: ?[]const u8 = null;
|
var sector: ?[]const u8 = null;
|
||||||
var geo: ?[]const u8 = null;
|
var geo: ?[]const u8 = null;
|
||||||
var asset_class: ?[]const u8 = null;
|
var asset_class: ?[]const u8 = null;
|
||||||
var pct: f64 = 100.0;
|
var pct: f64 = 100.0;
|
||||||
|
|
||||||
var field_iter = std.mem.splitScalar(u8, trimmed, ',');
|
for (record.fields) |field| {
|
||||||
while (field_iter.next()) |field| {
|
if (std.mem.eql(u8, field.key, "symbol")) {
|
||||||
const f = std.mem.trim(u8, field, &std.ascii.whitespace);
|
if (field.value) |v| symbol = strVal(v);
|
||||||
if (std.mem.startsWith(u8, f, "symbol::")) {
|
} else if (std.mem.eql(u8, field.key, "sector")) {
|
||||||
symbol = f["symbol::".len..];
|
if (field.value) |v| sector = strVal(v);
|
||||||
} else if (std.mem.startsWith(u8, f, "sector::")) {
|
} else if (std.mem.eql(u8, field.key, "geo")) {
|
||||||
sector = f["sector::".len..];
|
if (field.value) |v| geo = strVal(v);
|
||||||
} else if (std.mem.startsWith(u8, f, "geo::")) {
|
} else if (std.mem.eql(u8, field.key, "asset_class")) {
|
||||||
geo = f["geo::".len..];
|
if (field.value) |v| asset_class = strVal(v);
|
||||||
} else if (std.mem.startsWith(u8, f, "asset_class::")) {
|
} else if (std.mem.eql(u8, field.key, "pct")) {
|
||||||
asset_class = f["asset_class::".len..];
|
if (field.value) |v| pct = numVal(v);
|
||||||
} else if (std.mem.startsWith(u8, f, "pct:num:")) {
|
|
||||||
pct = std.fmt.parseFloat(f64, f["pct:num:".len..]) catch 100.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sym = symbol orelse continue; // skip lines without symbol
|
const sym = symbol orelse continue;
|
||||||
try entries.append(allocator, .{
|
try entries.append(allocator, .{
|
||||||
.symbol = try allocator.dupe(u8, sym),
|
.symbol = try allocator.dupe(u8, sym),
|
||||||
.sector = if (sector) |s| try allocator.dupe(u8, s) else null,
|
.sector = if (sector) |s| try allocator.dupe(u8, s) else null,
|
||||||
|
|
@ -100,6 +97,20 @@ pub fn parseClassificationFile(allocator: std.mem.Allocator, data: []const u8) !
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn strVal(v: srf.Value) ?[]const u8 {
|
||||||
|
return switch (v) {
|
||||||
|
.string => |s| s,
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn numVal(v: srf.Value) f64 {
|
||||||
|
return switch (v) {
|
||||||
|
.number => |n| n,
|
||||||
|
else => 100.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
test "parse classification file" {
|
test "parse classification file" {
|
||||||
const data =
|
const data =
|
||||||
\\#!srfv1
|
\\#!srfv1
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue