authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-07-26 23:56:45 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-07-26 23:56:45 -07:00
loga99e48702e92335a0b26c15fb3e5b31afc0ea7a7
treecf94654455a40d84d801cfe683877d8214947537
parenta15733be796221eee4dd2b3ff8c5508d7eca01a3

add initial code implementation


7 files changed, 144 insertions(+), 0 deletions(-)

.gitignore created+3
......@@ -0,0 +1,3 @@
1/zig-*
2/deps.zig
3/.zigmod
build.zig created+23
......@@ -0,0 +1,23 @@
1const std = @import("std");
2const deps = @import("./deps.zig");
3
4pub fn build(b: *std.build.Builder) void {
5 const target = b.standardTargetOptions(.{});
6
7 const mode = b.standardReleaseOptions();
8
9 const exe = b.addExecutable("zig-leven", "src/main.zig");
10 exe.setTarget(target);
11 exe.setBuildMode(mode);
12 deps.addAllTo(exe);
13 exe.install();
14
15 const run_cmd = exe.run();
16 run_cmd.step.dependOn(b.getInstallStep());
17 if (b.args) |args| {
18 run_cmd.addArgs(args);
19 }
20
21 const run_step = b.step("run", "Run the app");
22 run_step.dependOn(&run_cmd.step);
23}
src/lib.zig created+85
......@@ -0,0 +1,85 @@
1const std = @import("std");
2const range = @import("range").range;
3
4// // the naïve recursive implementation
5// pub fn leven(comptime T: type, a: []const T, b: []const T) usize {
6// if (b.len == 0) return a.len;
7// if (a.len == 0) return b.len;
8
9// if (a[0] == b[0]) return leven(T, a[1..], b[1..]);
10
11// return 1 + std.math.min3(
12// leven(T, a[1..], b),
13// leven(T, a, b[1..]),
14// leven(T, a[1..], b[1..]),
15// );
16// }
17
18pub fn leven(comptime T: type, alloc: *std.mem.Allocator, a: []const T, b: []const T) !usize {
19 if (std.mem.eql(T, a, b)) return 0;
20
21 var left = a;
22 var right = b;
23
24 if (left.len > right.len) {
25 left = b;
26 right = a;
27 }
28
29 var ll = left.len;
30 var rl = right.len;
31
32 {
33 const sl = suffixLen(T, a, b);
34 ll -= sl;
35 rl -= sl;
36 }
37
38 const start = prefixLen(T, a, b);
39 ll -= start;
40 rl -= start;
41
42 if (ll == 0) return rl;
43
44 var result: usize = 0;
45
46 const charCodeCache = try alloc.alloc(T, ll);
47 defer alloc.free(charCodeCache);
48
49 const array = try alloc.alloc(usize, ll);
50 defer alloc.free(array);
51
52 for (range(ll)) |_, i| {
53 charCodeCache[i] = left[start + i];
54 array[i] = i + 1;
55 }
56
57 for (range(rl)) |_, j| {
58 const bCharCode = right[start + j];
59 var temp = j;
60 result = j + 1;
61
62 for (range(ll)) |_, i| {
63 const temp2 = if (bCharCode == charCodeCache[i]) temp else temp + 1;
64 temp = array[i];
65 array[i] = if (temp > result) (if (temp2 > result) result + 1 else temp2) else (if (temp2 > temp) temp + 1 else temp2);
66 result = array[i];
67 }
68 }
69
70 return result;
71}
72
73fn prefixLen(comptime T: type, a: []const T, b: []const T) usize {
74 if (a.len == 0 or b.len == 0) return 0;
75 var i: usize = 0;
76 while (a[i] == b[i]) : (i += 1) {}
77 return i;
78}
79
80fn suffixLen(comptime T: type, a: []const T, b: []const T) usize {
81 if (a.len == 0 or b.len == 0) return 0;
82 var i: usize = 0;
83 while (a[a.len - 1 - i] == b[b.len - 1 - i]) : (i += 1) {}
84 return i;
85}
src/main.zig created+23
......@@ -0,0 +1,23 @@
1const std = @import("std");
2const leven = @import("leven").leven;
3
4pub fn main() !void {
5 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
6 defer _ = gpa.deinit();
7 const alloc = &gpa.allocator;
8
9 try std.testing.expectEqual(@as(usize, 1), try leven(u8, alloc, "a", "b"));
10 try std.testing.expectEqual(@as(usize, 1), try leven(u8, alloc, "ab", "ac"));
11 try std.testing.expectEqual(@as(usize, 1), try leven(u8, alloc, "ac", "bc"));
12 try std.testing.expectEqual(@as(usize, 1), try leven(u8, alloc, "abc", "axc"));
13 try std.testing.expectEqual(@as(usize, 3), try leven(u8, alloc, "kitten", "sitting"));
14 try std.testing.expectEqual(@as(usize, 6), try leven(u8, alloc, "xabxcdxxefxgx", "1ab2cd34ef5g6"));
15 try std.testing.expectEqual(@as(usize, 2), try leven(u8, alloc, "cat", "cow"));
16 try std.testing.expectEqual(@as(usize, 6), try leven(u8, alloc, "xabxcdxxefxgx", "abcdefg"));
17 try std.testing.expectEqual(@as(usize, 7), try leven(u8, alloc, "javawasneat", "scalaisgreat"));
18 try std.testing.expectEqual(@as(usize, 3), try leven(u8, alloc, "example", "samples"));
19 try std.testing.expectEqual(@as(usize, 6), try leven(u8, alloc, "sturgeon", "urgently"));
20 try std.testing.expectEqual(@as(usize, 6), try leven(u8, alloc, "levenshtein", "frankenstein"));
21 try std.testing.expectEqual(@as(usize, 5), try leven(u8, alloc, "distance", "difference"));
22 try std.testing.expectEqual(@as(usize, 2), try leven(u8, alloc, "因為我是中國人所以我會說中文", "因為我是英國人所以我會說英文"));
23}
zig.mod created+7
......@@ -0,0 +1,7 @@
1id: 96h80ezrvj7iqti7oar3lj30v0tg4cjii7yggcr0m9dhynfu
2name: leven
3main: src/lib.zig
4license: MIT
5description: Measure the difference between two slices using the Levenshtein distance algorithm
6dependencies:
7 - src: git https://github.com/nektro/zig-range
zigmod.lock created+2
......@@ -0,0 +1,2 @@
12
2git https://github.com/nektro/zig-range commit-890ca308fe09b3d5c866d5cfb3b3d7a95dbf939f
zigmod.sum created+1
......@@ -0,0 +1 @@
1blake3-09698753782139ab4877d08f33235170836f68b73e482b65cdee5637a6addf86 git/github.com/nektro/zig-range