# Generated by Snowball.Generator — do not edit by hand. defmodule Text.Stemmer.Stemmers.Persian do @moduledoc """ Snowball stemmer for persian. Generated from the canonical Snowball algorithm source. """ alias Snowball.Runtime # Among tables @a_0 [ {"یم", -1, 1, nil}, {"ایم", 0, 1, nil}, {"ای", -1, 1, nil}, {"است", -1, 1, nil}, {"اند", -1, 1, nil}, {"ید", -1, 1, nil}, {"اید", 5, 1, nil}, {"اس", -1, 1, nil} ] @a_1 [ {"م", -1, 1, nil}, {"یم", 0, 1, nil}, {"رفتیم", 1, 2, nil}, {"ام", 0, 1, nil}, {"رفتم", 0, 2, nil}, {"ان", -1, 3, nil}, {"ته", -1, 5, nil}, {"ده", -1, 4, nil}, {"نده", 7, 3, nil}, {"رفتی", -1, 2, nil}, {"د", -1, 1, nil}, {"اند", 10, 1, nil}, {"رفتاند", 11, 2, nil}, {"ید", 10, 1, nil}, {"رفتید", 13, 2, nil} ] @a_2 [ {"ام", -1, 1, nil}, {"ین", -1, 10, nil}, {"ترین", 1, 16, nil}, {"ان", -1, 9, nil}, {"یان", 3, 3, nil}, {"بان", 3, 12, nil}, {"گان", 3, 4, nil}, {"انه", -1, 18, nil}, {"گاه", -1, 11, nil}, {"انی", -1, 6, nil}, {"یی", -1, 15, nil}, {"های", -1, 5, nil}, {"گی", -1, 13, nil}, {"ها", -1, 7, nil}, {"ناک", -1, 21, nil}, {"یت", -1, 14, nil}, {"ات", -1, 8, nil}, {"مند", -1, 19, nil}, {"وار", -1, 20, nil}, {"گار", -1, 22, nil}, {"تر", -1, 17, nil}, {"اش", -1, 2, nil} ] @a_3 [ {"اساتید", -1, 2, nil}, {"اخبار", -1, 1, nil} ] @a_4 [ {"گیلان", -1, 1, nil}, {"آلمان", -1, 1, nil}, {"مسلمان", -1, 1, nil}, {"سلیمان", -1, 1, nil}, {"ایمان", -1, 1, nil}, {"پیمان", -1, 1, nil}, {"ساختمان", -1, 1, nil}, {"رمان", -1, 1, nil}, {"قهرمان", 7, 1, nil}, {"کرمان", 7, 1, nil}, {"درمان", 7, 1, nil}, {"همزمان", -1, 1, nil}, {"سازمان", -1, 1, nil}, {"آسمان", -1, 1, nil}, {"یونان", -1, 1, nil}, {"لبنان", -1, 1, nil}, {"اصفهان", -1, 1, nil}, {"پایان", -1, 1, nil}, {"بیان", -1, 1, nil}, {"جریان", -1, 1, nil}, {"امکان", -1, 1, nil}, {"آذربایجان", -1, 1, nil}, {"همدان", -1, 1, nil}, {"خاندان", -1, 1, nil}, {"زندان", -1, 1, nil}, {"میزان", -1, 1, nil}, {"آتشفشان", -1, 1, nil}, {"نشان", -1, 1, nil}, {"ایشان", -1, 1, nil}, {"پریشان", -1, 1, nil}, {"کهکشان", -1, 1, nil}, {"درخشان", -1, 1, nil}, {"سلطان", -1, 1, nil} ] @a_5 [ {"وان", -1, -1, nil}, {"ستان", -1, -1, nil}, {"ران", -1, -1, nil}, {"سان", -1, -1, nil} ] @a_6 [ {"", -1, 8, nil}, {" ", 0, 7, nil}, {"أ", 0, 4, nil}, {"ؤ", 0, 5, nil}, {"إ", 0, 4, nil}, {"ئ", 0, 2, nil}, {"ة", 0, 3, nil}, {"ك", 0, 1, nil}, {"ي", 0, 2, nil}, {"ہ", 0, 3, nil}, {"\u200D", 0, 6, nil} ] @a_7 [ {"می\u200C", -1, 2, nil}, {"نمی\u200C", -1, 1, nil} ] @doc """ Stem a word. ### Arguments * `word` is a UTF-8 binary. ### Returns * The stemmed UTF-8 binary. """ @spec stem(binary()) :: binary() def stem(word) when is_binary(word) do state = Runtime.new(word) |> init_vars() state = run_stem(state) Runtime.assign_to(state) end defp init_vars(state), do: %{state | vars: %{p1: 0, remove_verb_person_endings: false, saw_present_prefix: false}} defp run_stem(%Runtime{} = state) do {_, state} = r_stem(state) state end # Snowball runtime helpers. defp snowball_do_f(state, fun) do saved_c = state.cursor {_, s} = fun.(state) %{s | cursor: saved_c} end defp snowball_test_b(state, fun) do rel = state.limit - state.cursor case fun.(state) do {:ok, s} -> {:ok, %{s | cursor: s.limit - rel}} {:fail, s} -> {:fail, %{s | cursor: s.limit - rel}} end end defp snowball_try(state, fun) do rel = state.limit - state.cursor case fun.(state) do {:ok, s} -> s {:fail, s} -> %{s | cursor: s.limit - rel} end end defp snowball_or(state, fun1, fun2) do rel = state.limit - state.cursor case fun1.(state) do {:ok, s} -> {:ok, s} {:fail, s} -> fun2.(%{s | cursor: s.limit - rel}) end end defp lift(state, :fail), do: {:fail, state} defp lift(_state, %Runtime{} = s), do: {:ok, s} defp next_codepoint(%Runtime{cursor: c, limit: lim, current: cur} = state) do case Runtime.codepoint_at(cur, c, lim) do {_cp, size} -> {:ok, %{state | cursor: c + size}} :error -> {:fail, state} end end defp r_Stem_Verb(%Runtime{} = state) do snowball_or(state, fn state -> (fn -> state = %{state | ket: state.cursor} case Runtime.find_among_b(state, @a_0) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = %{s | bra: s.cursor} case result do 1 -> case (fn state -> r_R1(state) end).(state) do {:ok, state} -> {:ok, Runtime.slice_del(state)} r -> r end _ -> {:ok, state} end end end).() end, fn state -> (fn -> state = %{state | ket: state.cursor} case Runtime.find_among_b(state, @a_1) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = %{s | bra: s.cursor} case result do 1 -> case (fn state -> if state.vars[:remove_verb_person_endings], do: {:ok, state}, else: {:fail, state} end).(state) do {:ok, state} -> case (fn state -> r_R1(state) end).(state) do {:ok, state} -> {:ok, Runtime.slice_del(state)} r -> r end r -> r end 2 -> {:ok, Runtime.slice_from(state, "رفت")} 3 -> case (fn state -> r_R1(state) end).(state) do {:ok, state} -> case (fn state -> {:ok, Runtime.slice_del(state)} end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:remove_verb_person_endings], true)} end r -> r end 4 -> case (fn state -> (fn state -> saved_c = state.cursor case (fn state -> if state.cursor <= state.limit_backward, do: {:ok, state}, else: {:fail, state} end).(state) do {:ok, s} -> {:fail, %{s | cursor: saved_c}} {:fail, s} -> {:ok, %{s | cursor: saved_c}} end end).(state) end).(state) do {:ok, state} -> case (fn state -> {:ok, Runtime.slice_from(state, "د")} end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:remove_verb_person_endings], true)} end r -> r end 5 -> case (fn state -> (fn state -> saved_c = state.cursor case (fn state -> if state.cursor <= state.limit_backward, do: {:ok, state}, else: {:fail, state} end).(state) do {:ok, s} -> {:fail, %{s | cursor: saved_c}} {:fail, s} -> {:ok, %{s | cursor: saved_c}} end end).(state) end).(state) do {:ok, state} -> case (fn state -> {:ok, Runtime.slice_from(state, "ت")} end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:remove_verb_person_endings], true)} end r -> r end _ -> {:ok, state} end end end).() end) end defp r_Stem_Noun_or_Adjective(%Runtime{} = state) do snowball_or(state, fn state -> r_Irregular_Noun(state) end, fn state -> (fn -> case (fn state -> (fn -> target = state.vars[:p1] if target < state.limit_backward or target > state.limit do {:fail, state} else {:ok, %{state | cursor: target}} end end).() end).(state) do {:fail, _} -> {:fail, state} {:ok, limit_state} -> old_lb = state.limit_backward state = %{state | limit_backward: limit_state.cursor} case (fn state -> (fn -> state = %{state | ket: state.cursor} case Runtime.find_among_b(state, @a_2) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = %{s | bra: s.cursor} case result do 1 -> {:ok, Runtime.slice_del(state)} 2 -> {:ok, Runtime.slice_del(state)} 3 -> {:ok, Runtime.slice_del(state)} 4 -> {:ok, Runtime.slice_del(state)} 5 -> {:ok, Runtime.slice_del(state)} 6 -> {:ok, Runtime.slice_del(state)} 7 -> {:ok, Runtime.slice_del(state)} 8 -> {:ok, Runtime.slice_del(state)} 9 -> {:ok, Runtime.slice_del(state)} 10 -> {:ok, Runtime.slice_del(state)} 11 -> {:ok, Runtime.slice_del(state)} 12 -> {:ok, Runtime.slice_del(state)} 13 -> {:ok, Runtime.slice_del(state)} 14 -> {:ok, Runtime.slice_del(state)} 15 -> {:ok, Runtime.slice_del(state)} 16 -> {:ok, Runtime.slice_del(state)} 17 -> case (fn state -> (fn state -> saved_c = state.cursor case (fn state -> if state.cursor <= state.limit_backward, do: {:ok, state}, else: {:fail, state} end).(state) do {:ok, s} -> {:fail, %{s | cursor: saved_c}} {:fail, s} -> {:ok, %{s | cursor: saved_c}} end end).(state) end).(state) do {:ok, state} -> {:ok, Runtime.slice_del(state)} r -> r end 18 -> {:ok, Runtime.slice_del(state)} 19 -> {:ok, Runtime.slice_del(state)} 20 -> {:ok, Runtime.slice_del(state)} 21 -> {:ok, Runtime.slice_del(state)} 22 -> {:ok, Runtime.slice_del(state)} _ -> {:ok, state} end end end).() end).(state) do {:ok, s} -> {:ok, %{s | limit_backward: old_lb}} {:fail, s} -> {:fail, %{s | limit_backward: old_lb}} end end end).() end) end defp r_Irregular_Noun(%Runtime{} = state) do (fn -> state = %{state | ket: state.cursor} case Runtime.find_among_b(state, @a_3) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = %{s | bra: s.cursor} case result do 1 -> {:ok, Runtime.slice_from(state, "خبر")} 2 -> {:ok, Runtime.slice_from(state, "استاد")} _ -> {:ok, state} end end end).() end defp r_AN_Exception(%Runtime{} = state) do (fn -> case Runtime.find_among_b(state, @a_4) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = s case result do 1 -> if state.cursor <= state.limit_backward, do: {:ok, state}, else: {:fail, state} _ -> {:ok, s} end end end).() end defp r_Protect_Lexical_AN(%Runtime{} = state) do case (fn state -> (fn state -> saved_c = state.cursor case (fn state -> r_AN_Exception(state) end).(state) do {:ok, s} -> {:fail, %{s | cursor: saved_c}} {:fail, s} -> {:ok, %{s | cursor: saved_c}} end end).(state) end).(state) do {:ok, state} -> (fn state -> saved_c = state.cursor case (fn state -> (fn -> case Runtime.find_among_b(state, @a_5) do :fail -> {:fail, state} {%Runtime{} = s, _} -> {:ok, s} end end).() end).(state) do {:ok, s} -> {:fail, %{s | cursor: saved_c}} {:fail, s} -> {:ok, %{s | cursor: saved_c}} end end).(state) r -> r end end defp r_R1(%Runtime{} = state) do if state.vars[:p1] <= state.cursor, do: {:ok, state}, else: {:fail, state} end defp r_Normalize_Characters(%Runtime{} = state) do (fn loop_fn -> loop_fn.(loop_fn, state) end).(fn loop_fn, state -> case (fn state -> (fn -> state = %{state | bra: state.cursor} case Runtime.find_among(state, @a_6) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = %{s | ket: s.cursor} case result do 1 -> {:ok, Runtime.slice_from(state, "ک")} 2 -> {:ok, Runtime.slice_from(state, "ی")} 3 -> {:ok, Runtime.slice_from(state, "ه")} 4 -> {:ok, Runtime.slice_from(state, "ا")} 5 -> {:ok, Runtime.slice_from(state, "و")} 6 -> {:ok, Runtime.slice_del(state)} 7 -> {:ok, Runtime.slice_del(state)} 8 -> next_codepoint(state) _ -> {:ok, state} end end end).() end).(state) do {:ok, s} -> loop_fn.(loop_fn, s) {:fail, s} -> {:ok, %{s | cursor: state.cursor}} end end) end defp r_Prefixes(%Runtime{} = state) do (fn -> state = %{state | bra: state.cursor} case Runtime.find_among(state, @a_7) do :fail -> {:fail, state} {%Runtime{} = s, result} -> state = %{s | ket: s.cursor} case result do 1 -> case (fn state -> (fn -> n = 2 Enum.reduce_while(1..max(n, 0)//1, {:ok, state}, fn _, {:ok, s} -> case next_codepoint(s) do {:ok, s2} -> {:cont, {:ok, s2}} {:fail, _} -> {:halt, {:fail, state}} end end) end).() end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:saw_present_prefix], true)} r -> r end 2 -> case (fn state -> (fn -> n = 2 Enum.reduce_while(1..max(n, 0)//1, {:ok, state}, fn _, {:ok, s} -> case next_codepoint(s) do {:ok, s2} -> {:cont, {:ok, s2}} {:fail, _} -> {:halt, {:fail, state}} end end) end).() end).(state) do {:ok, state} -> case (fn state -> {:ok, Runtime.slice_del(state)} end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:saw_present_prefix], true)} end r -> r end _ -> {:ok, state} end end end).() end defp r_Delete_ZWNJ(%Runtime{} = state) do (fn loop_fn -> loop_fn.(loop_fn, state) end).(fn loop_fn, state -> case (fn state -> (fn loop_fn -> loop_fn.(loop_fn, state) end).(fn loop_fn, state -> v = state.cursor case (fn state -> case (fn state -> {:ok, %{state | bra: state.cursor}} end).(state) do {:ok, state} -> case (fn state -> lift(state, Runtime.eq_s(state, "\u200C")) end).(state) do {:ok, state} -> case (fn state -> {:ok, %{state | ket: state.cursor}} end).(state) do {:ok, state} -> {:ok, Runtime.slice_del(state)} end r -> r end end end).(state) do {:ok, s} -> {:ok, %{s | cursor: v}} {:fail, _} -> case next_codepoint(%{state | cursor: v}) do {:ok, s} -> loop_fn.(loop_fn, s) {:fail, _} -> {:fail, state} end end end) end).(state) do {:ok, s} -> loop_fn.(loop_fn, s) {:fail, s} -> {:ok, %{s | cursor: state.cursor}} end end) end defp r_stem(%Runtime{} = state) do case (fn state -> {:ok, put_in(state.vars[:saw_present_prefix], false)} end).(state) do {:ok, state} -> case (fn state -> {:ok, snowball_do_f(state, fn state -> r_Normalize_Characters(state) end)} end).(state) do {:ok, state} -> case (fn state -> {:ok, snowball_do_f(state, fn state -> r_Prefixes(state) end)} end).(state) do {:ok, state} -> case (fn state -> {:ok, snowball_do_f(state, fn state -> r_Delete_ZWNJ(state) end)} end).(state) do {:ok, state} -> case (fn state -> {:ok, put_in(state.vars[:p1], state.limit)} end).(state) do {:ok, state} -> case (fn state -> {:ok, snowball_do_f(state, fn state -> case (fn state -> (fn -> n = 3 Enum.reduce_while(1..max(n, 0)//1, {:ok, state}, fn _, {:ok, s} -> case next_codepoint(s) do {:ok, s2} -> {:cont, {:ok, s2}} {:fail, _} -> {:halt, {:fail, state}} end end) end).() end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:p1], state.cursor)} r -> r end end)} end).(state) do {:ok, state} -> (fn state -> old_cursor = state.cursor old_lb = state.limit_backward state = %{state | cursor: state.limit, limit_backward: old_cursor} {tag, s} = (fn state -> (fn loop_fn -> loop_fn.(loop_fn, state) end).(fn loop_fn, state -> case (fn state -> snowball_test_b(state, fn state -> case (fn state -> {:ok, put_in(state.vars[:remove_verb_person_endings], false)} end).(state) do {:ok, state} -> case (fn state -> {:ok, snowball_try(state, fn state -> case (fn state -> if state.vars[:saw_present_prefix], do: {:ok, state}, else: {:fail, state} end).(state) do {:ok, state} -> {:ok, put_in(state.vars[:remove_verb_person_endings], true)} r -> r end end)} end).(state) do {:ok, state} -> case (fn state -> r_Protect_Lexical_AN(state) end).(state) do {:ok, state} -> snowball_or(state, fn state -> r_Stem_Noun_or_Adjective(state) end, fn state -> r_Stem_Verb(state) end) r -> r end end end end) end).(state) do {:ok, s} -> loop_fn.(loop_fn, s) {:fail, s} -> {:ok, %{s | cursor: state.cursor}} end end) end).(state) {tag, %{s | cursor: old_cursor, limit_backward: old_lb}} end).(state) end end end end end end end end