Packages
caffeine_lang
5.4.2
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang@string_distance.erl
-module(caffeine_lang@string_distance).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/string_distance.gleam").
-export([levenshtein/2, closest_match/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/caffeine_lang/string_distance.gleam", 44).
-spec build_row_loop(
list(integer()),
list(binary()),
binary(),
list(integer()),
integer()
) -> {list(integer()), integer()}.
build_row_loop(Prev_row, B_remaining, A_char, Acc, Prev_val) ->
case {B_remaining, Prev_row} of
{[], _} ->
{Acc, Prev_val};
{[B_char | B_rest], [Diag | Prev_rest]} ->
Above = case Prev_rest of
[V | _] ->
V;
[] ->
0
end,
Cost = case A_char =:= B_char of
true ->
0;
false ->
1
end,
Val = gleam@int:min(
Prev_val + 1,
gleam@int:min(Above + 1, Diag + Cost)
),
build_row_loop(Prev_rest, B_rest, A_char, [Val | Acc], Val);
{_, []} ->
{Acc, Prev_val}
end.
-file("src/caffeine_lang/string_distance.gleam", 33).
?DOC(" Builds one row of the Levenshtein matrix.\n").
-spec build_row(list(integer()), list(binary()), binary(), integer()) -> list(integer()).
build_row(Prev_row, B_graphemes, A_char, Initial_val) ->
{Row, _} = build_row_loop(
Prev_row,
B_graphemes,
A_char,
[Initial_val],
Initial_val
),
lists:reverse(Row).
-file("src/caffeine_lang/string_distance.gleam", 9).
?DOC(" Computes the Levenshtein edit distance between two strings.\n").
-spec levenshtein(binary(), binary()) -> integer().
levenshtein(A, B) ->
A_graphemes = gleam@string:to_graphemes(A),
B_graphemes = gleam@string:to_graphemes(B),
B_len = erlang:length(B_graphemes),
Initial_row = gleam@int:range(B_len, -1, [], fun(Acc, I) -> [I | Acc] end),
Result_row = gleam@list:index_fold(
A_graphemes,
Initial_row,
fun(Prev_row, A_char, I@1) ->
build_row(Prev_row, B_graphemes, A_char, I@1 + 1)
end
),
case gleam@list:last(Result_row) of
{ok, D} ->
D;
{error, nil} ->
0
end.
-file("src/caffeine_lang/string_distance.gleam", 71).
?DOC(
" Returns the closest match from a list of candidates, if within threshold.\n"
" Threshold: distance <= max(2, ceil(length(target) * 0.4)).\n"
).
-spec closest_match(binary(), list(binary())) -> gleam@option:option(binary()).
closest_match(Target, Candidates) ->
Target_len = string:length(Target),
Threshold = gleam@int:max(
2,
erlang:trunc((erlang:float(Target_len) * 0.4) + 0.99)
),
Result = gleam@list:fold(
Candidates,
none,
fun(Best, Candidate) ->
Dist = levenshtein(Target, Candidate),
case Dist > Threshold of
true ->
Best;
false ->
case Best of
none ->
{some, {Candidate, Dist}};
{some, {_, Best_dist}} ->
case Dist < Best_dist of
true ->
{some, {Candidate, Dist}};
false ->
Best
end
end
end
end
),
case Result of
{some, {Name, _}} ->
{some, Name};
none ->
none
end.