| 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 |