کمک در جهت تحلیل و یادگیری شبهه کد تبدیل عدد فارسی به انگلیسی در الکسیر

با درود خدمت شما.

نیازمندی پروژه:

در یک پروژه ای نیاز است کاربر در تقویم فارسی ( شمسی , جلالی ) یک تاریخ را انتخاب کند و این تاریخ در دیتابیس به صورت میلادی ذخیره شود. مثال از یک خروجی ۱۲/۱۱/۱۳۰۴

انجام تبدیل اعداد

در این بین با مطلبی در انجمن الکسیر به شرح زیر آشنا شدم که کتابخانه ای برای انجام این دسته کار ها از قبل آماده شده بود:

نیازمند تحلیل و تفهیم کد:

در فایل https://github.com/alisinabh/Numero/blob/master/lib/numero.ex من دنبال مبدل کد گشتم و تونستم بخشی از این کتابخانه را تفکیک کنم برای انجام فقط کار خودم یعنی تبدیل عدد فارسی به انگلیسی که در زیر این شبهه کد قرار دارد

  @zero_starts ~c[0٠۰߀०০੦૦୦௦౦೦൦෦๐໐༠၀႐០᠐᥆᧐᪀᪐᭐᮰᱀᱐꘠꣐꤀꧐꧰꩐꯰0𐒠𑁦𑃰𑄶𑇐𑋰𑑐𑓐𑙐𑛀𑜰𑣠𑱐𑵐𖩠𖭐𝟎𝟘𝟢𝟬𝟶𞥐]

  @spec normalize(String.t()) :: String.t()
  def normalize(number_str) do
    number_str
    |> replace_chars("")
  end

  Enum.each(@zero_starts, fn start ->
    Enum.each(start..(start + 9), fn digit ->
      def replace_chars(<<unquote(digit)::utf8, tail::binary>>, acc),
        do: replace_chars(tail, acc <> <<unquote(digit) - unquote(start) + 48>>)
    end)
  end)

  def replace_chars("", acc), do: acc

  def replace_chars(<<char::utf8, tail::binary>>, acc),
    do: replace_chars(tail, acc <> <<char::utf8>>)

سوالات بنده به ترتیب:

۱. در خیلی از کتابخانه ها و کد های الکسیر دیدم که به این صورت می نویسند

@spec normalize(String.t()) :: String.t()
  def normalize(number_str) do
    number_str
    |> replace_chars("")
  end

یعنی بالای فانکشن می یاند اسم خودشو صدا می زنند و مثلا می نویسند String.t

@spec normalize(String.t()) :: String.t()

خوب این به چه معنی هست و برای چه کاری انجام می شه از صورت فانکشن مشخصه تا حدودی که فکر کنم چک می کنه استرینگ هست یا خیر یا تبدیل می کنه به استرینگ .

اول چرا اینطور نوشته شده ؟ دوم چرا دوبار استرینگ صدا زده و این :: به چه معنی هست در وسط



۲. جالبه نمی دونستم که می شه فانکشن رو به این صورت هم نوشت

  Enum.each(@zero_starts, fn start ->
    Enum.each(start..(start + 9), fn digit ->
      def replace_chars(<<unquote(digit)::utf8, tail::binary>>, acc),
        do: replace_chars(tail, acc <> <<unquote(digit) - unquote(start) + 48>>)
    end)
  end)

یعنی با Enum.each شروع کرد . تا اونجایی که من از این فانکشن فهمیدم اینکه می یاند اون حروف بالا رو تک به تک می ده به فانکشن replace_chars و استرینگ هارو بر اساس یونیکد تفکیک می کنه و به صورت بازگشتی دوباره می ده به فانکشن replace_chars که به شرح زیر هست:

  def replace_chars("", acc), do: acc

  def replace_chars(<<char::utf8, tail::binary>>, acc),
    do: replace_chars(tail, acc <> <<char::utf8>>)

حالا من اینجا نتونستم بفهمم چیجوری عدد فارسی رو شناسایی کرده و تبدیل به انگلیسی نموده

تشکر

1 Like
  1. سوال اول
@spec normalize(String.t()) :: String.t()

خودشو صدا نمیزنه این عبارت قسمتی از typespec که تایپ function مینویسه
https://hexdocs.pm/elixir/typespecs.html
نوشته function normalize
ورودی string میگیره و string برمیگردونه
با اینکه الیکسیر زبانه دینامیک typespec با استفاده از dialyzer چک میکنه که تایپ درسته

سوال دوم
این متاپروگرامینگ که داره برای هر داده در Enum یک function مینویسه بصورت دینامیک

1 Like

درود خدمت سام عزیز:

ممنون که کلمه کلیدیشو دادید دنبالش می گفتم ولی نمی دونستم چی سرچ بزنم حالا برام سوال شده با این توضیحات بنده برای تمام فانکشن هام که خروجی و ورودی دارند آیا باید چنین کاروی بکنم یعنی typespec بزارم؟

1 Like

اضافه کردن تایپ spec اختیاری هستش

1 Like

بیشتر سام عزیز منظورم این بود که چقدر تاثیر بر روند کدنویسی ما دارد؟ آخه بلخره ما در حال تست فانکشن هستیم و همینطور خروجی مدنظرشو باز در جای دیگه استفاده می کنیم!!

اگر شما تو spec نوشته باشید که فانکشن string میگره بعد تو کد Int بدی با dialyzer در زمان کامپایل خطا میگیری شبیه زبان های ستاتیک این میل خودشماست که از این قابلیت استفاده کنید یا نه. میتونه جلو بعضی خطا ها رو بگیره به همین دلیل اکثر کتابخانه ها typespec دارند

1 Like