Packages

Gleam implementation of the Lancaster (Paice/Husk) Stemmer

Current section

Files

Jump to
lancaster_stemmer src lancaster_stemmer.erl
Raw

src/lancaster_stemmer.erl

-module(lancaster_stemmer).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lancaster_stemmer.gleam").
-export([stem/2, load_rules/1, default_rules/0]).
-export_type([rule/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque rule() :: {rule,
binary(),
binary(),
binary(),
boolean(),
integer(),
binary(),
boolean()}.
-file("src/lancaster_stemmer.gleam", 304).
-spec rule_matches(rule(), binary(), boolean()) -> boolean().
rule_matches(Rule, Word, Stem_intact) ->
case not Stem_intact andalso erlang:element(5, Rule) of
true ->
false;
false ->
gleam_stdlib:string_ends_with(Word, erlang:element(4, Rule))
end.
-file("src/lancaster_stemmer.gleam", 311).
-spec apply_rule(rule(), binary()) -> binary().
apply_rule(Rule, Word) ->
<<(gleam@string:drop_end(Word, erlang:element(6, Rule)))/binary,
(erlang:element(7, Rule))/binary>>.
-file("src/lancaster_stemmer.gleam", 327).
-spec is_valid_internal(binary(), integer()) -> boolean().
is_valid_internal(Word, Length) ->
case Word of
<<""/utf8>> ->
false;
<<"a"/utf8, Rest/binary>> ->
((Length + 1) + string:length(Rest)) >= 3;
<<"e"/utf8, Rest/binary>> ->
((Length + 1) + string:length(Rest)) >= 3;
<<"i"/utf8, Rest/binary>> ->
((Length + 1) + string:length(Rest)) >= 3;
<<"o"/utf8, Rest/binary>> ->
((Length + 1) + string:length(Rest)) >= 3;
<<"u"/utf8, Rest/binary>> ->
((Length + 1) + string:length(Rest)) >= 3;
<<"y"/utf8, Rest/binary>> ->
((Length + 1) + string:length(Rest)) >= 3;
_ ->
is_valid_internal(gleam@string:drop_start(Word, 1), Length + 1)
end.
-file("src/lancaster_stemmer.gleam", 315).
-spec is_valid(binary()) -> boolean().
is_valid(Word) ->
case Word of
<<""/utf8>> ->
false;
<<"a"/utf8, Rest/binary>> ->
Rest /= <<""/utf8>>;
<<"e"/utf8, Rest/binary>> ->
Rest /= <<""/utf8>>;
<<"i"/utf8, Rest/binary>> ->
Rest /= <<""/utf8>>;
<<"o"/utf8, Rest/binary>> ->
Rest /= <<""/utf8>>;
<<"u"/utf8, Rest/binary>> ->
Rest /= <<""/utf8>>;
_ ->
is_valid_internal(Word, 0)
end.
-file("src/lancaster_stemmer.gleam", 268).
-spec do_stem(binary(), gleam@dict:dict(binary(), list(rule())), boolean()) -> binary().
do_stem(Word, Rules, Intact) ->
case begin
_pipe = gleam@string:reverse(Word),
gleam_stdlib:string_pop_grapheme(_pipe)
end of
{ok, {Letter, _}} ->
case gleam_stdlib:map_get(Rules, Letter) of
{ok, Specific_rules} ->
{Stem, Restem, Intact@1} = gleam@list:fold_until(
Specific_rules,
{Word, false, Intact},
fun(State, Rule) ->
case rule_matches(Rule, Word, Intact) of
true ->
Result = apply_rule(Rule, Word),
case is_valid(Result) of
false ->
{continue, State};
true ->
{stop,
{Result,
erlang:element(8, Rule),
false}}
end;
false ->
{continue, State}
end
end
),
case Restem of
true ->
do_stem(Stem, Rules, Intact@1);
false ->
Stem
end;
{error, _} ->
Word
end;
{error, _} ->
Word
end.
-file("src/lancaster_stemmer.gleam", 258).
?DOC(
" Lancaster (Paice-Husk) stemming algorithm\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" lancaster_stemmer.stem(\"Gleam\", lancaster_stemmer.stem.default_rules())\n"
" // -> gleam\n"
" ```\n"
"\n"
" ```gleam\n"
" lancaster_stemmer.stem(\"fancy\", lancaster_stemmer.stem.default_rules())\n"
" // -> fant\n"
" ```\n"
).
-spec stem(binary(), gleam@dict:dict(binary(), list(rule()))) -> binary().
stem(Word, Rules) ->
Word@1 = string:lowercase(Word),
case is_valid(Word@1) of
true ->
do_stem(Word@1, Rules, true);
false ->
Word@1
end.
-file("src/lancaster_stemmer.gleam", 438).
-spec parse_rule_remove(binary(), binary()) -> {ok, {integer(), binary()}} |
{error, nil}.
parse_rule_remove(Rule, Acc) ->
case Rule of
<<"0"/utf8, Rest/binary>> ->
Number = <<"0"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"1"/utf8, Rest/binary>> ->
Number = <<"1"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"2"/utf8, Rest/binary>> ->
Number = <<"2"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"3"/utf8, Rest/binary>> ->
Number = <<"3"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"4"/utf8, Rest/binary>> ->
Number = <<"4"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"5"/utf8, Rest/binary>> ->
Number = <<"5"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"6"/utf8, Rest/binary>> ->
Number = <<"6"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"7"/utf8, Rest/binary>> ->
Number = <<"7"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"8"/utf8, Rest/binary>> ->
Number = <<"8"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
<<"9"/utf8, Rest/binary>> ->
Number = <<"9"/utf8>>,
parse_rule_remove(Rest, <<Acc/binary, Number/binary>>);
_ when Acc =:= <<""/utf8>> ->
{error, nil};
_ ->
gleam@result:'try'(
gleam_stdlib:parse_int(Acc),
fun(I) -> {ok, {I, Rule}} end
)
end.
-file("src/lancaster_stemmer.gleam", 458).
-spec parse_rule_text(binary(), binary()) -> {ok, {binary(), binary()}} |
{error, nil}.
parse_rule_text(Rule, Acc) ->
case Rule of
<<"a"/utf8, Rest/binary>> ->
Letter = <<"a"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"b"/utf8, Rest/binary>> ->
Letter = <<"b"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"c"/utf8, Rest/binary>> ->
Letter = <<"c"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"d"/utf8, Rest/binary>> ->
Letter = <<"d"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"e"/utf8, Rest/binary>> ->
Letter = <<"e"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"f"/utf8, Rest/binary>> ->
Letter = <<"f"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"g"/utf8, Rest/binary>> ->
Letter = <<"g"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"h"/utf8, Rest/binary>> ->
Letter = <<"h"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"i"/utf8, Rest/binary>> ->
Letter = <<"i"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"j"/utf8, Rest/binary>> ->
Letter = <<"j"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"k"/utf8, Rest/binary>> ->
Letter = <<"k"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"l"/utf8, Rest/binary>> ->
Letter = <<"l"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"m"/utf8, Rest/binary>> ->
Letter = <<"m"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"n"/utf8, Rest/binary>> ->
Letter = <<"n"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"o"/utf8, Rest/binary>> ->
Letter = <<"o"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"p"/utf8, Rest/binary>> ->
Letter = <<"p"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"q"/utf8, Rest/binary>> ->
Letter = <<"q"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"r"/utf8, Rest/binary>> ->
Letter = <<"r"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"s"/utf8, Rest/binary>> ->
Letter = <<"s"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"t"/utf8, Rest/binary>> ->
Letter = <<"t"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"u"/utf8, Rest/binary>> ->
Letter = <<"u"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"v"/utf8, Rest/binary>> ->
Letter = <<"v"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"w"/utf8, Rest/binary>> ->
Letter = <<"w"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"x"/utf8, Rest/binary>> ->
Letter = <<"x"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"y"/utf8, Rest/binary>> ->
Letter = <<"y"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"z"/utf8, Rest/binary>> ->
Letter = <<"z"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"A"/utf8, Rest/binary>> ->
Letter = <<"A"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"B"/utf8, Rest/binary>> ->
Letter = <<"B"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"C"/utf8, Rest/binary>> ->
Letter = <<"C"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"D"/utf8, Rest/binary>> ->
Letter = <<"D"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"E"/utf8, Rest/binary>> ->
Letter = <<"E"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"F"/utf8, Rest/binary>> ->
Letter = <<"F"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"G"/utf8, Rest/binary>> ->
Letter = <<"G"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"H"/utf8, Rest/binary>> ->
Letter = <<"H"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"I"/utf8, Rest/binary>> ->
Letter = <<"I"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"J"/utf8, Rest/binary>> ->
Letter = <<"J"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"K"/utf8, Rest/binary>> ->
Letter = <<"K"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"L"/utf8, Rest/binary>> ->
Letter = <<"L"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"M"/utf8, Rest/binary>> ->
Letter = <<"M"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"N"/utf8, Rest/binary>> ->
Letter = <<"N"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"O"/utf8, Rest/binary>> ->
Letter = <<"O"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"P"/utf8, Rest/binary>> ->
Letter = <<"P"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"Q"/utf8, Rest/binary>> ->
Letter = <<"Q"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"R"/utf8, Rest/binary>> ->
Letter = <<"R"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"S"/utf8, Rest/binary>> ->
Letter = <<"S"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"T"/utf8, Rest/binary>> ->
Letter = <<"T"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"U"/utf8, Rest/binary>> ->
Letter = <<"U"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"V"/utf8, Rest/binary>> ->
Letter = <<"V"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"W"/utf8, Rest/binary>> ->
Letter = <<"W"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"X"/utf8, Rest/binary>> ->
Letter = <<"X"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"Y"/utf8, Rest/binary>> ->
Letter = <<"Y"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
<<"Z"/utf8, Rest/binary>> ->
Letter = <<"Z"/utf8>>,
parse_rule_text(Rest, <<Acc/binary, Letter/binary>>);
_ ->
{ok, {Acc, Rule}}
end.
-file("src/lancaster_stemmer.gleam", 395).
-spec process_rule(binary(), integer()) -> {ok, rule()} | {error, nil}.
process_rule(Rule, Id) ->
Rule@1 = gleam@string:trim(Rule),
gleam@result:'try'(
parse_rule_text(Rule@1, <<""/utf8>>),
fun(_use0) ->
{Suffix, Rule@2} = _use0,
gleam@bool:guard(
Suffix =:= <<""/utf8>>,
{error, nil},
fun() ->
{Intact, Rule@4} = case Rule@2 of
<<"*"/utf8, Rule@3/binary>> ->
{true, Rule@3};
_ ->
{false, Rule@2}
end,
gleam@result:'try'(
parse_rule_remove(Rule@4, <<""/utf8>>),
fun(_use0@1) ->
{Remove, Rule@5} = _use0@1,
gleam@result:'try'(
parse_rule_text(Rule@5, <<""/utf8>>),
fun(_use0@2) ->
{Append, Rule@6} = _use0@2,
gleam@result:'try'(case Rule@6 of
<<">"/utf8, _/binary>> ->
{ok, true};
<<"."/utf8, _/binary>> ->
{ok, false};
_ ->
{error, nil}
end, fun(Restem) ->
Id@1 = <<<<<<<<<<<<<<<<"("/utf8,
(erlang:integer_to_binary(
Id
))/binary>>/binary,
":"/utf8>>/binary,
Suffix/binary>>/binary,
((case Intact of
true ->
<<"*"/utf8>>;
false ->
<<""/utf8>>
end))/binary>>/binary,
(erlang:integer_to_binary(
Remove
))/binary>>/binary,
Append/binary>>/binary,
((case Restem of
true ->
<<">"/utf8>>;
false ->
<<"."/utf8>>
end))/binary>>/binary,
")"/utf8>>,
gleam@result:'try'(
gleam@string:first(Suffix),
fun(Letter) ->
Suffix@1 = gleam@string:reverse(
Suffix
),
{ok,
{rule,
Id@1,
Letter,
Suffix@1,
Intact,
Remove,
Append,
Restem}}
end
)
end)
end
)
end
)
end
)
end
).
-file("src/lancaster_stemmer.gleam", 380).
-spec process_rules(binary(), splitter:splitter(), list(rule()), integer()) -> {ok,
list(rule())} |
{error, nil}.
process_rules(Rules, Split, Acc, Id) ->
case splitter_ffi:split(Split, Rules) of
{<<"end0."/utf8, _/binary>>, _, _} ->
{ok, Acc};
{Rule, _, Rest} ->
gleam@result:'try'(
process_rule(Rule, Id),
fun(Rule@1) ->
process_rules(Rest, Split, [Rule@1 | Acc], Id + 1)
end
)
end.
-file("src/lancaster_stemmer.gleam", 359).
?DOC(
" Constructs a ruleset from the specified file\n"
"\n"
" Format of the file is as follows:\n"
" Each line contains a specific rule (order matters)\n"
" The rule consists of a string made up of the following parts\n"
" | Rule part | Description |\n"
" | ------ | ------ |\n"
" |suffix|the reverse of the required suffix, e.g. the suffix for winning, ing would be specified gni|\n"
" |* (optional)|if the rule is only to be used if a previous rule has not been applied then add an asterisk. For example ht*2. only applies if th is the final suffix, so the stem of breath would be brea but the stem of breathe would be breath because the suffix e has already been removed|\n"
" |number of chars to remove|this is the number of characters to remove after the suffix has been matched. For example psychoanalytic has the suffix ytic of which 3 characters should be removed to retain psychoanaly, this would be 'city3'. This can be 0|\n"
" |append string (optional)|this is the characters that are appended after the match and removal of characters|\n"
" |> or .|If > then you can continue stemming process after this one, if . then stemming stops|\n"
"\n"
" So for example with the `psychoanalytic` stem of `psychoanalys` the rule would be `ytic3s.`\n"
).
-spec load_rules(binary()) -> {ok, gleam@dict:dict(binary(), list(rule()))} |
{error, nil}.
load_rules(Filename) ->
case simplifile:read(Filename) of
{error, _} ->
{error, nil};
{ok, Rules} ->
Split = splitter:new([<<"\n"/utf8>>, <<"\r\n"/utf8>>]),
gleam@result:'try'(
process_rules(Rules, Split, [], 1),
fun(Rules@1) ->
_pipe = gleam@list:fold(
Rules@1,
maps:new(),
fun(Acc, Rule) ->
gleam@dict:upsert(
Acc,
erlang:element(3, Rule),
fun(Rules@2) -> case Rules@2 of
{some, Rules@3} ->
[Rule | Rules@3];
none ->
[Rule]
end end
)
end
),
{ok, _pipe}
end
)
end.
-file("src/lancaster_stemmer.gleam", 241).
?DOC(" Constructs the default ruleset\n").
-spec default_rules() -> gleam@dict:dict(binary(), list(rule())).
default_rules() ->
maps:from_list(
[{<<"a"/utf8>>,
[{rule,
<<"(1:ai*2.)"/utf8>>,
<<"a"/utf8>>,
<<"ia"/utf8>>,
true,
2,
<<""/utf8>>,
false},
{rule,
<<"(2:a*1.)"/utf8>>,
<<"a"/utf8>>,
<<"a"/utf8>>,
true,
1,
<<""/utf8>>,
false}]},
{<<"b"/utf8>>,
[{rule,
<<"(3:bb1.)"/utf8>>,
<<"b"/utf8>>,
<<"bb"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"c"/utf8>>,
[{rule,
<<"(4:city3s.)"/utf8>>,
<<"c"/utf8>>,
<<"ytic"/utf8>>,
false,
3,
<<"s"/utf8>>,
false},
{rule,
<<"(5:ci2>)"/utf8>>,
<<"c"/utf8>>,
<<"ic"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(6:cn1t>)"/utf8>>,
<<"c"/utf8>>,
<<"nc"/utf8>>,
false,
1,
<<"t"/utf8>>,
true}]},
{<<"d"/utf8>>,
[{rule,
<<"(7:dd1.)"/utf8>>,
<<"d"/utf8>>,
<<"dd"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(8:dei3y>)"/utf8>>,
<<"d"/utf8>>,
<<"ied"/utf8>>,
false,
3,
<<"y"/utf8>>,
true},
{rule,
<<"(9:deec2ss.)"/utf8>>,
<<"d"/utf8>>,
<<"ceed"/utf8>>,
false,
2,
<<"ss"/utf8>>,
false},
{rule,
<<"(10:dee1.)"/utf8>>,
<<"d"/utf8>>,
<<"eed"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(11:de2>)"/utf8>>,
<<"d"/utf8>>,
<<"ed"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(12:dooh4>)"/utf8>>,
<<"d"/utf8>>,
<<"hood"/utf8>>,
false,
4,
<<""/utf8>>,
true}]},
{<<"e"/utf8>>,
[{rule,
<<"(13:e1>)"/utf8>>,
<<"e"/utf8>>,
<<"e"/utf8>>,
false,
1,
<<""/utf8>>,
true}]},
{<<"f"/utf8>>,
[{rule,
<<"(14:feil1v.)"/utf8>>,
<<"f"/utf8>>,
<<"lief"/utf8>>,
false,
1,
<<"v"/utf8>>,
false},
{rule,
<<"(15:fi2>)"/utf8>>,
<<"f"/utf8>>,
<<"if"/utf8>>,
false,
2,
<<""/utf8>>,
true}]},
{<<"g"/utf8>>,
[{rule,
<<"(16:gni3>)"/utf8>>,
<<"g"/utf8>>,
<<"ing"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(17:gai3y.)"/utf8>>,
<<"g"/utf8>>,
<<"iag"/utf8>>,
false,
3,
<<"y"/utf8>>,
false},
{rule,
<<"(18:ga2>)"/utf8>>,
<<"g"/utf8>>,
<<"ag"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(19:gg1.)"/utf8>>,
<<"g"/utf8>>,
<<"gg"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"h"/utf8>>,
[{rule,
<<"(20:ht*2.)"/utf8>>,
<<"h"/utf8>>,
<<"th"/utf8>>,
true,
2,
<<""/utf8>>,
false},
{rule,
<<"(21:hsiug5ct.)"/utf8>>,
<<"h"/utf8>>,
<<"guish"/utf8>>,
false,
5,
<<"ct"/utf8>>,
false},
{rule,
<<"(22:hsi3>)"/utf8>>,
<<"h"/utf8>>,
<<"ish"/utf8>>,
false,
3,
<<""/utf8>>,
true}]},
{<<"i"/utf8>>,
[{rule,
<<"(23:i*1.)"/utf8>>,
<<"i"/utf8>>,
<<"i"/utf8>>,
true,
1,
<<""/utf8>>,
false},
{rule,
<<"(24:i1y>)"/utf8>>,
<<"i"/utf8>>,
<<"i"/utf8>>,
false,
1,
<<"y"/utf8>>,
true}]},
{<<"j"/utf8>>,
[{rule,
<<"(25:ji1d.)"/utf8>>,
<<"j"/utf8>>,
<<"ij"/utf8>>,
false,
1,
<<"d"/utf8>>,
false},
{rule,
<<"(26:juf1s.)"/utf8>>,
<<"j"/utf8>>,
<<"fuj"/utf8>>,
false,
1,
<<"s"/utf8>>,
false},
{rule,
<<"(27:ju1d.)"/utf8>>,
<<"j"/utf8>>,
<<"uj"/utf8>>,
false,
1,
<<"d"/utf8>>,
false},
{rule,
<<"(28:jo1d.)"/utf8>>,
<<"j"/utf8>>,
<<"oj"/utf8>>,
false,
1,
<<"d"/utf8>>,
false},
{rule,
<<"(29:jeh1r.)"/utf8>>,
<<"j"/utf8>>,
<<"hej"/utf8>>,
false,
1,
<<"r"/utf8>>,
false},
{rule,
<<"(30:jrev1t.)"/utf8>>,
<<"j"/utf8>>,
<<"verj"/utf8>>,
false,
1,
<<"t"/utf8>>,
false},
{rule,
<<"(31:jsim2t.)"/utf8>>,
<<"j"/utf8>>,
<<"misj"/utf8>>,
false,
2,
<<"t"/utf8>>,
false},
{rule,
<<"(32:jn1d.)"/utf8>>,
<<"j"/utf8>>,
<<"nj"/utf8>>,
false,
1,
<<"d"/utf8>>,
false},
{rule,
<<"(33:j1s.)"/utf8>>,
<<"j"/utf8>>,
<<"j"/utf8>>,
false,
1,
<<"s"/utf8>>,
false}]},
{<<"l"/utf8>>,
[{rule,
<<"(34:lbaifi6.)"/utf8>>,
<<"l"/utf8>>,
<<"ifiabl"/utf8>>,
false,
6,
<<""/utf8>>,
false},
{rule,
<<"(35:lbai4y.)"/utf8>>,
<<"l"/utf8>>,
<<"iabl"/utf8>>,
false,
4,
<<"y"/utf8>>,
false},
{rule,
<<"(36:lba3>)"/utf8>>,
<<"l"/utf8>>,
<<"abl"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(37:lbi3.)"/utf8>>,
<<"l"/utf8>>,
<<"ibl"/utf8>>,
false,
3,
<<""/utf8>>,
false},
{rule,
<<"(38:lib2l>)"/utf8>>,
<<"l"/utf8>>,
<<"bil"/utf8>>,
false,
2,
<<"l"/utf8>>,
true},
{rule,
<<"(39:lc1.)"/utf8>>,
<<"l"/utf8>>,
<<"cl"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(40:lufi4y.)"/utf8>>,
<<"l"/utf8>>,
<<"iful"/utf8>>,
false,
4,
<<"y"/utf8>>,
false},
{rule,
<<"(41:luf3>)"/utf8>>,
<<"l"/utf8>>,
<<"ful"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(42:lu2.)"/utf8>>,
<<"l"/utf8>>,
<<"ul"/utf8>>,
false,
2,
<<""/utf8>>,
false},
{rule,
<<"(43:lai3>)"/utf8>>,
<<"l"/utf8>>,
<<"ial"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(44:lau3>)"/utf8>>,
<<"l"/utf8>>,
<<"ual"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(45:la2>)"/utf8>>,
<<"l"/utf8>>,
<<"al"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(46:ll1.)"/utf8>>,
<<"l"/utf8>>,
<<"ll"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"m"/utf8>>,
[{rule,
<<"(47:mui3.)"/utf8>>,
<<"m"/utf8>>,
<<"ium"/utf8>>,
false,
3,
<<""/utf8>>,
false},
{rule,
<<"(48:mu*2.)"/utf8>>,
<<"m"/utf8>>,
<<"um"/utf8>>,
true,
2,
<<""/utf8>>,
false},
{rule,
<<"(49:msi3>)"/utf8>>,
<<"m"/utf8>>,
<<"ism"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(50:mm1.)"/utf8>>,
<<"m"/utf8>>,
<<"mm"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"n"/utf8>>,
[{rule,
<<"(51:nois4j>)"/utf8>>,
<<"n"/utf8>>,
<<"sion"/utf8>>,
false,
4,
<<"j"/utf8>>,
true},
{rule,
<<"(52:noix4ct.)"/utf8>>,
<<"n"/utf8>>,
<<"xion"/utf8>>,
false,
4,
<<"ct"/utf8>>,
false},
{rule,
<<"(53:noi3>)"/utf8>>,
<<"n"/utf8>>,
<<"ion"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(54:nai3>)"/utf8>>,
<<"n"/utf8>>,
<<"ian"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(55:na2>)"/utf8>>,
<<"n"/utf8>>,
<<"an"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(56:nee0.)"/utf8>>,
<<"n"/utf8>>,
<<"een"/utf8>>,
false,
0,
<<""/utf8>>,
false},
{rule,
<<"(57:ne2>)"/utf8>>,
<<"n"/utf8>>,
<<"en"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(58:nn1.)"/utf8>>,
<<"n"/utf8>>,
<<"nn"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"p"/utf8>>,
[{rule,
<<"(59:pihs4>)"/utf8>>,
<<"p"/utf8>>,
<<"ship"/utf8>>,
false,
4,
<<""/utf8>>,
true},
{rule,
<<"(60:pp1.)"/utf8>>,
<<"p"/utf8>>,
<<"pp"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"r"/utf8>>,
[{rule,
<<"(61:re2>)"/utf8>>,
<<"r"/utf8>>,
<<"er"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(62:rae0.)"/utf8>>,
<<"r"/utf8>>,
<<"ear"/utf8>>,
false,
0,
<<""/utf8>>,
false},
{rule,
<<"(63:ra2.)"/utf8>>,
<<"r"/utf8>>,
<<"ar"/utf8>>,
false,
2,
<<""/utf8>>,
false},
{rule,
<<"(64:ro2>)"/utf8>>,
<<"r"/utf8>>,
<<"or"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(65:ru2>)"/utf8>>,
<<"r"/utf8>>,
<<"ur"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(66:rr1.)"/utf8>>,
<<"r"/utf8>>,
<<"rr"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(67:rt1>)"/utf8>>,
<<"r"/utf8>>,
<<"tr"/utf8>>,
false,
1,
<<""/utf8>>,
true},
{rule,
<<"(68:rei3y>)"/utf8>>,
<<"r"/utf8>>,
<<"ier"/utf8>>,
false,
3,
<<"y"/utf8>>,
true}]},
{<<"s"/utf8>>,
[{rule,
<<"(69:sei3y>)"/utf8>>,
<<"s"/utf8>>,
<<"ies"/utf8>>,
false,
3,
<<"y"/utf8>>,
true},
{rule,
<<"(70:sis2.)"/utf8>>,
<<"s"/utf8>>,
<<"sis"/utf8>>,
false,
2,
<<""/utf8>>,
false},
{rule,
<<"(71:si2>)"/utf8>>,
<<"s"/utf8>>,
<<"is"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(72:ssen4>)"/utf8>>,
<<"s"/utf8>>,
<<"ness"/utf8>>,
false,
4,
<<""/utf8>>,
true},
{rule,
<<"(73:ss0.)"/utf8>>,
<<"s"/utf8>>,
<<"ss"/utf8>>,
false,
0,
<<""/utf8>>,
false},
{rule,
<<"(74:suo3>)"/utf8>>,
<<"s"/utf8>>,
<<"ous"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(75:su*2.)"/utf8>>,
<<"s"/utf8>>,
<<"us"/utf8>>,
true,
2,
<<""/utf8>>,
false},
{rule,
<<"(76:s*1>)"/utf8>>,
<<"s"/utf8>>,
<<"s"/utf8>>,
true,
1,
<<""/utf8>>,
true},
{rule,
<<"(77:s0.)"/utf8>>,
<<"s"/utf8>>,
<<"s"/utf8>>,
false,
0,
<<""/utf8>>,
false}]},
{<<"t"/utf8>>,
[{rule,
<<"(78:tacilp4y.)"/utf8>>,
<<"t"/utf8>>,
<<"plicat"/utf8>>,
false,
4,
<<"y"/utf8>>,
false},
{rule,
<<"(79:ta2>)"/utf8>>,
<<"t"/utf8>>,
<<"at"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(80:tnem4>)"/utf8>>,
<<"t"/utf8>>,
<<"ment"/utf8>>,
false,
4,
<<""/utf8>>,
true},
{rule,
<<"(81:tne3>)"/utf8>>,
<<"t"/utf8>>,
<<"ent"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(82:tna3>)"/utf8>>,
<<"t"/utf8>>,
<<"ant"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(83:tpir2b.)"/utf8>>,
<<"t"/utf8>>,
<<"ript"/utf8>>,
false,
2,
<<"b"/utf8>>,
false},
{rule,
<<"(84:tpro2b.)"/utf8>>,
<<"t"/utf8>>,
<<"orpt"/utf8>>,
false,
2,
<<"b"/utf8>>,
false},
{rule,
<<"(85:tcud1.)"/utf8>>,
<<"t"/utf8>>,
<<"duct"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(86:tpmus2.)"/utf8>>,
<<"t"/utf8>>,
<<"sumpt"/utf8>>,
false,
2,
<<""/utf8>>,
false},
{rule,
<<"(87:tpec2iv.)"/utf8>>,
<<"t"/utf8>>,
<<"cept"/utf8>>,
false,
2,
<<"iv"/utf8>>,
false},
{rule,
<<"(88:tulo2v.)"/utf8>>,
<<"t"/utf8>>,
<<"olut"/utf8>>,
false,
2,
<<"v"/utf8>>,
false},
{rule,
<<"(89:tsis0.)"/utf8>>,
<<"t"/utf8>>,
<<"sist"/utf8>>,
false,
0,
<<""/utf8>>,
false},
{rule,
<<"(90:tsi3>)"/utf8>>,
<<"t"/utf8>>,
<<"ist"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(91:tt1.)"/utf8>>,
<<"t"/utf8>>,
<<"tt"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"u"/utf8>>,
[{rule,
<<"(92:uqi3.)"/utf8>>,
<<"u"/utf8>>,
<<"iqu"/utf8>>,
false,
3,
<<""/utf8>>,
false},
{rule,
<<"(93:ugo1.)"/utf8>>,
<<"u"/utf8>>,
<<"ogu"/utf8>>,
false,
1,
<<""/utf8>>,
false}]},
{<<"v"/utf8>>,
[{rule,
<<"(94:vis3j>)"/utf8>>,
<<"v"/utf8>>,
<<"siv"/utf8>>,
false,
3,
<<"j"/utf8>>,
true},
{rule,
<<"(95:vie0.)"/utf8>>,
<<"v"/utf8>>,
<<"eiv"/utf8>>,
false,
0,
<<""/utf8>>,
false},
{rule,
<<"(96:vi2>)"/utf8>>,
<<"v"/utf8>>,
<<"iv"/utf8>>,
false,
2,
<<""/utf8>>,
true}]},
{<<"y"/utf8>>,
[{rule,
<<"(97:ylb1>)"/utf8>>,
<<"y"/utf8>>,
<<"bly"/utf8>>,
false,
1,
<<""/utf8>>,
true},
{rule,
<<"(98:yli3y>)"/utf8>>,
<<"y"/utf8>>,
<<"ily"/utf8>>,
false,
3,
<<"y"/utf8>>,
true},
{rule,
<<"(99:ylp0.)"/utf8>>,
<<"y"/utf8>>,
<<"ply"/utf8>>,
false,
0,
<<""/utf8>>,
false},
{rule,
<<"(100:yl2>)"/utf8>>,
<<"y"/utf8>>,
<<"ly"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(101:ygo1.)"/utf8>>,
<<"y"/utf8>>,
<<"ogy"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(102:yhp1.)"/utf8>>,
<<"y"/utf8>>,
<<"phy"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(103:ymo1.)"/utf8>>,
<<"y"/utf8>>,
<<"omy"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(104:ypo1.)"/utf8>>,
<<"y"/utf8>>,
<<"opy"/utf8>>,
false,
1,
<<""/utf8>>,
false},
{rule,
<<"(105:yti3>)"/utf8>>,
<<"y"/utf8>>,
<<"ity"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(106:yte3>)"/utf8>>,
<<"y"/utf8>>,
<<"ety"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(107:ytl2.)"/utf8>>,
<<"y"/utf8>>,
<<"lty"/utf8>>,
false,
2,
<<""/utf8>>,
false},
{rule,
<<"(108:yrtsi5.)"/utf8>>,
<<"y"/utf8>>,
<<"istry"/utf8>>,
false,
5,
<<""/utf8>>,
false},
{rule,
<<"(109:yra3>)"/utf8>>,
<<"y"/utf8>>,
<<"ary"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(110:yro3>)"/utf8>>,
<<"y"/utf8>>,
<<"ory"/utf8>>,
false,
3,
<<""/utf8>>,
true},
{rule,
<<"(111:yfi3.)"/utf8>>,
<<"y"/utf8>>,
<<"ify"/utf8>>,
false,
3,
<<""/utf8>>,
false},
{rule,
<<"(112:ycn2t>)"/utf8>>,
<<"y"/utf8>>,
<<"ncy"/utf8>>,
false,
2,
<<"t"/utf8>>,
true},
{rule,
<<"(113:yca3>)"/utf8>>,
<<"y"/utf8>>,
<<"acy"/utf8>>,
false,
3,
<<""/utf8>>,
true}]},
{<<"z"/utf8>>,
[{rule,
<<"(114:zi2>)"/utf8>>,
<<"z"/utf8>>,
<<"iz"/utf8>>,
false,
2,
<<""/utf8>>,
true},
{rule,
<<"(115:zy1s.)"/utf8>>,
<<"z"/utf8>>,
<<"yz"/utf8>>,
false,
1,
<<"s"/utf8>>,
false}]}]
).