-module(starfuzz@phonetic). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/starfuzz/phonetic.gleam"). -export([soundex/1, same_soundex/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. ?MODULEDOC( " A module providing phonetic matching capabilities.\n" " Phonetic matching indexes words by how they sound (homophones),\n" " allowing comparison regardless of spelling variations (e.g., \"Robert\" and \"Rupert\").\n" ). -file("src/starfuzz/phonetic.gleam", 8). -spec replacement(binary()) -> binary(). replacement(Char) -> case Char of <<"B"/utf8>> -> <<"1"/utf8>>; <<"F"/utf8>> -> <<"1"/utf8>>; <<"P"/utf8>> -> <<"1"/utf8>>; <<"V"/utf8>> -> <<"1"/utf8>>; <<"C"/utf8>> -> <<"2"/utf8>>; <<"G"/utf8>> -> <<"2"/utf8>>; <<"J"/utf8>> -> <<"2"/utf8>>; <<"K"/utf8>> -> <<"2"/utf8>>; <<"Q"/utf8>> -> <<"2"/utf8>>; <<"S"/utf8>> -> <<"2"/utf8>>; <<"X"/utf8>> -> <<"2"/utf8>>; <<"Z"/utf8>> -> <<"2"/utf8>>; <<"D"/utf8>> -> <<"3"/utf8>>; <<"T"/utf8>> -> <<"3"/utf8>>; <<"L"/utf8>> -> <<"4"/utf8>>; <<"M"/utf8>> -> <<"5"/utf8>>; <<"N"/utf8>> -> <<"5"/utf8>>; <<"R"/utf8>> -> <<"6"/utf8>>; _ -> <<"*"/utf8>> end. -file("src/starfuzz/phonetic.gleam", 68). -spec pad_zero(binary()) -> binary(). pad_zero(S) -> case string:length(S) of Len when Len < 4 -> pad_zero(<>); _ -> gleam@string:slice(S, 0, 4) end. -file("src/starfuzz/phonetic.gleam", 26). ?DOC( " Encodes the input string into its Soundex representation (typically a letter followed by 3 numbers).\n" "\n" " Under the Soundex rules:\n" " - Letter casing is ignored.\n" " - Adjacent duplicated sounds are collapsed.\n" " - 'H' and 'W' act as silently omitted vowels unless they split different consonant sounds.\n" ). -spec soundex(binary()) -> binary(). soundex(Input) -> case gleam@string:is_empty(Input) of true -> <<""/utf8>>; false -> Upper = string:uppercase(Input), Chars = gleam@string:to_graphemes(Upper), First@1 = case gleam@list:first(Chars) of {ok, First} -> First; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"starfuzz/phonetic"/utf8>>, function => <<"soundex"/utf8>>, line => 33, value => _assert_fail, start => 1009, 'end' => 1049, pattern_start => 1020, pattern_end => 1029}) end, Tail@1 = case gleam@list:rest(Chars) of {ok, Tail} -> Tail; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"starfuzz/phonetic"/utf8>>, function => <<"soundex"/utf8>>, line => 34, value => _assert_fail@1, start => 1056, 'end' => 1094, pattern_start => 1067, pattern_end => 1075}) end, Last_initial = replacement(First@1), {Res_chars, _, _} = gleam@list:fold( Tail@1, {[First@1], Last_initial, 1}, fun(State, Char) -> {Acc, Last, Len} = State, case Len >= 4 of true -> State; false -> Sub = replacement(Char), case Sub /= <<"*"/utf8>> of true -> case Sub /= Last of true -> {[Sub | Acc], Sub, Len + 1}; false -> {Acc, Sub, Len} end; false -> case (Char /= <<"H"/utf8>>) andalso (Char /= <<"W"/utf8>>) of true -> {Acc, <<"*"/utf8>>, Len}; false -> {Acc, Last, Len} end end end end ), Result_string = gleam@string:join( lists:reverse(Res_chars), <<""/utf8>> ), pad_zero(Result_string) end. -file("src/starfuzz/phonetic.gleam", 76). ?DOC(" Compares if two strings result in the exact same Soundex code.\n"). -spec same_soundex(binary(), binary()) -> boolean(). same_soundex(A, B) -> soundex(A) =:= soundex(B).