| author | |
| committer | |
| log | a99e48702e92335a0b26c15fb3e5b31afc0ea7a7 |
| tree | cf94654455a40d84d801cfe683877d8214947537 |
| parent | a15733be796221eee4dd2b3ff8c5508d7eca01a3 |
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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const deps = @import("./deps.zig"); | ||
| 3 | |||
| 4 | pub 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const 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 | |||
| 18 | pub 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 | |||
| 73 | fn 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 | |||
| 80 | fn 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const leven = @import("leven").leven; | ||
| 3 | |||
| 4 | pub 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 @@ | ||
| 1 | id: 96h80ezrvj7iqti7oar3lj30v0tg4cjii7yggcr0m9dhynfu | ||
| 2 | name: leven | ||
| 3 | main: src/lib.zig | ||
| 4 | license: MIT | ||
| 5 | description: Measure the difference between two slices using the Levenshtein distance algorithm | ||
| 6 | dependencies: | ||
| 7 | - src: git https://github.com/nektro/zig-range | ||
zigmod.lock created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | 2 | ||
| 2 | git https://github.com/nektro/zig-range commit-890ca308fe09b3d5c866d5cfb3b3d7a95dbf939f | ||
zigmod.sum created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | blake3-09698753782139ab4877d08f33235170836f68b73e482b65cdee5637a6addf86 git/github.com/nektro/zig-range | ||