divan/RMuseum/Services/Implementation/LanguageUtils.cs
Hamid Reza Mohammadi a6e7d4f4e6 tajik api fix
2026-08-07 16:28:35 +03:30

399 lines
15 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DNTPersianUtils.Core;
using RMuseum.Models.Ganjoor;
using RMuseum.Models.Ganjoor.ViewModels;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace RMuseum.Services.Implementation
{
/// <summary>
/// Language Utilitis
/// </summary>
public static class LanguageUtils
{
/// <summary>
/// Persian Alphabet
/// </summary>
public const string PersianAlphabet = "آابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیئؤء";
/// <summary>
/// English Alphabet
/// </summary>
public const string EnglishLowerCaseAlphabet = "abcdefghijklmnopqrstuvwxyz";
/// <summary>
/// Check to see if input Contains Only Specific Characters
/// </summary>
/// <param name="input"></param>
/// <param name="specfics"></param>
/// <param name="additional"></param>
/// <returns></returns>
public static string GetFirstNotMatchingCharacter(string input, string specfics, string additional = "")
{
string all = specfics + additional;
foreach (char c in input)
if (all.IndexOf(c) == -1)
return (c + "");
return "";
}
/// <summary>
/// make text searchable
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string MakeTextSearchable(string text)
{
return text.Replace("‌", " ")//replace zwnj with space
.Replace("ّ", "")//tashdid
.Replace("َ", "")//a
.Replace("ِ", "")//e
.Replace("ُ", "")//o
.Replace("ً", "")//an
.Replace("ٍ", "")//en
.Replace("ٌ", "")//on
.Replace(".", "")//dot
.Replace("،", "")//virgool
.Replace("!", "")
.Replace("؟", "")
.Replace("ٔ", "")//ye
.Replace(":", "")
.Replace("ئ", "ی")
.Replace("؛", "")
.Replace(";", "")
.Replace("*", "")
.Replace(")", "")
.Replace("(", "")
.Replace("[", "")
.Replace("]", "")
.Replace("\"", "")
.Replace("'", "")
.Replace("«", "")
.Replace("»", "")
.Replace("ْ", "")//sokoon
;
}
public static string CleanTextForTransileration(string text)
{
if (string.IsNullOrEmpty(text)) return text;
return text.Replace("‌", " ")//replace zwnj with space
.Replace("ّ", "")//tashdid
.Replace("َ", "")//a
.Replace("ِ", "")//e
.Replace("ُ", "")//o
.Replace("ً", "")//an
.Replace("ٍ", "")//en
.Replace("ٌ", "")//on
.Replace("ٔ", "")//ye
.Replace("ْ", "")//sokoon
;
}
/// <summary>
/// simple, best-effort Perso-Arabic -> Tajik Cyrillic letter substitution.
/// NOT a linguistically correct transliteration: Perso-Arabic script does not
/// write short vowels, so a letter-by-letter map cannot recover them (that's
/// why a dedicated tool like persian-tajik.ir exists, and why the bulk of
/// TajikGanjoor's content comes from real TajikPoems/TajikCats/TajikPoets rows
/// rather than on-the-fly conversion). This exists only as a fallback for
/// spots - like a neighbouring poem's excerpt on the next/previous nav - that
/// don't have a proper Tajik translation in the database yet, so at least
/// something in Cyrillic is shown instead of raw Perso-Arabic script.
/// </summary>
private static readonly Dictionary<char, string> _persianToTajikMap = new Dictionary<char, string>()
{
['آ'] = "о",
['ا'] = "о",
['ب'] = "б",
['پ'] = "п",
['ت'] = "т",
['ث'] = "с",
['ج'] = "ҷ",
['چ'] = "ч",
['ح'] = "ҳ",
['خ'] = "х",
['د'] = "д",
['ذ'] = "з",
['ر'] = "р",
['ز'] = "з",
['ژ'] = "ж",
['س'] = "с",
['ش'] = "ш",
['ص'] = "с",
['ض'] = "з",
['ط'] = "т",
['ظ'] = "з",
['ع'] = "ъ",
['غ'] = "ғ",
['ف'] = "ф",
['ق'] = "қ",
['ک'] = "к",
['ك'] = "к",
['گ'] = "г",
['ل'] = "л",
['م'] = "м",
['ن'] = "н",
['و'] = "в",
['ه'] = "ҳ",
['ی'] = "ӣ",
['ي'] = "ӣ",
['ئ'] = "ъ",
['ؤ'] = "в",
['ء'] = "ъ",
['ة'] = "ат",
['؟'] = "?",
['،'] = ",",
['؛'] = ";",
['۰'] = "0",
['۱'] = "1",
['۲'] = "2",
['۳'] = "3",
['۴'] = "4",
['۵'] = "5",
['۶'] = "6",
['۷'] = "7",
['۸'] = "8",
['۹'] = "9",
};
public static string TransliteratePersianToTajik(string text)
{
if (string.IsNullOrEmpty(text)) return text;
text = CleanTextForTransileration(text);
var sb = new System.Text.StringBuilder(text.Length);
foreach (char c in text)
{
sb.Append(_persianToTajikMap.TryGetValue(c, out string mapped) ? mapped : c.ToString());
}
return sb.ToString();
}
public static string SameSoundLetters(string text)
{
return text.Replace("آ", "ا").Replace("ث", "س").Replace("ح", "ه").Replace("ذ", "ز").Replace("ص", "س").Replace("ض", "ز").Replace("ط", "ت").Replace("ظ", "ز").Replace("غ", "ق");
}
private static string PrepareTextForFindingRhyme(string text)
{
return MakeTextSearchable(text)
.Replace("لله", "للاه")
.Replace("آ", "ا")
.Replace("‍", "")
.Replace("‏", "")
.Replace("‌", "")
.Replace(" ", "")
.Trim();
}
/// <summary>
/// find rhyme
/// </summary>
/// <param name="verses"></param>
/// <param name="secondPhase"></param>
/// <param name="bandCouplets"></param>
/// <param name="tryWholeVerses"></param>
/// <returns></returns>
public static GanjooRhymeAnalysisResult FindRhyme(List<GanjoorVerse> verses, bool secondPhase = false, bool bandCouplets = false, bool tryWholeVerses = false)
{
try
{
List<string> verseTextList = verses.Count == 2 || tryWholeVerses ? verses.Select(v => v.Text).ToList()
: bandCouplets ?
verses.Where(v => v.VersePosition == VersePosition.CenteredVerse2).Select(v => v.Text).ToList()
: verses.Where(v => v.VersePosition == VersePosition.Left).Select(v => v.Text).ToList();
if (verseTextList.Count > 1)
{
string rhyme = PrepareTextForFindingRhyme(verseTextList[0]);
if (string.IsNullOrEmpty(rhyme))
{
return new GanjooRhymeAnalysisResult()
{
Rhyme = "",
FailVerse = verseTextList[0]
};
}
if (secondPhase)
{
if (rhyme.Length > 0 && rhyme[rhyme.Length - 1] == 'ی')
rhyme = rhyme.Remove(rhyme.Length - 1);
}
for (int j = 1; j < verseTextList.Count; j++)
{
string verseText = PrepareTextForFindingRhyme(verseTextList[j]);
if (secondPhase)
{
if (verseText.Length > 0 && verseText[verseText.Length - 1] == 'ی')
{
verseText = verseText.Remove(verseText.Length - 1);
}
}
string oldRhyme = rhyme;
rhyme = "";
int i = oldRhyme.Length - 1;
while (
(oldRhyme[i] == verseText[verseText.Length - oldRhyme.Length + i])
||
(
(oldRhyme[i] == 'ذ')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'د')
)
||
(
(oldRhyme[i] == 'د')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'ذ')
)
||
(
(oldRhyme[i] == 'ی')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'ا')
)
||
(
(oldRhyme[i] == 'ا')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'ی')
)
||
(oldRhyme[i] == verseText[verseText.Length - oldRhyme.Length + i])
||
(
(oldRhyme[i] == 'پ')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'ب')
)
||
(
(oldRhyme[i] == 'ب')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'پ')
)
||
(oldRhyme[i] == 'ة')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'ت')
||
(oldRhyme[i] == 'ت')
&&
(verseText[verseText.Length - oldRhyme.Length + i] == 'ة')
)
{
rhyme = oldRhyme[i] + rhyme;
i--;
if (i == -1)
break;
}
if (rhyme.Length == 0)
{
if (verses.Count == 2 && verseTextList.Count == 2)
{
rhyme = PrepareTextForFindingRhyme(verseTextList[1]);
if(rhyme.Length > 50)
{
rhyme = "";
}
return new GanjooRhymeAnalysisResult()
{
Rhyme = rhyme, //rhyme.Length > 50 condition check removed to search using prosody meters
FailVerse = "",
};
}
return new GanjooRhymeAnalysisResult()
{
Rhyme = "",
FailVerse = verseText
};
}
}
if (!secondPhase)
{
if (string.IsNullOrEmpty(rhyme))
{
return FindRhyme(verses, true);
}
}
////rhyme.Length > 50 condition check removed to search using prosody meters
/*if (rhyme.Length > 50)
{
return new GanjooRhymeAnalysisResult()
{
Rhyme = "",
FailVerse = "",
};
}*/
if (rhyme.Length > 50)
{
rhyme = "";
}
return new GanjooRhymeAnalysisResult()
{
Rhyme = rhyme,
FailVerse = ""
};
}
}
catch
{
}
return new GanjooRhymeAnalysisResult() { Rhyme = "", FailVerse = "" };
}
/// <summary>
/// format money
/// </summary>
/// <param name="amount"></param>
/// <returns></returns>
public static string FormatMoney(decimal amount)
{
return amount.ToString("N0", new CultureInfo("fa-IR")).ToPersianNumbers();
}
/// <summary>
/// format datetime
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static string FormatDate(DateTime dateTime)
{
return $"{dateTime.ToPersianYearMonthDay().Day.ToPersianNumbers()}م {PersianCulture.GetPersianMonthName(dateTime.ToPersianYearMonthDay().Month)} {dateTime.ToPersianYearMonthDay().Year.ToPersianNumbers()}";
}
/// <summary>
/// short date
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static string FormatInShortDate(DateTime dateTime)
{
return dateTime.Year < 623 ? "" : $"{dateTime.ToPersianYearMonthDay().Year.ToPersianNumbers()}/{dateTime.ToPersianYearMonthDay().Month.ToString().PadLeft(2, '0').ToPersianNumbers()}/{dateTime.ToPersianYearMonthDay().Day.ToString().PadLeft(2, '0').ToPersianNumbers()}";
}
}
}